home *** CD-ROM | disk | FTP | other *** search
/ Libris Britannia 4 / science library(b).zip / science library(b) / UTILITIE / CONVERSI / H400.ZIP / ZSIM22.ZIP / CPMBIOS.ASM < prev    next >
Assembly Source File  |  1993-06-16  |  97KB  |  4,204 lines

  1. ;
  2. ; BIOS FUER DEN CP/M EMULATOR
  3. ;
  4. ;
  5. ; (C) 1990,1991,1992,1993 by Jürgen Weber
  6. ;
  7. ; Version: 1.0
  8. ;          1.1     Load/Save disparameters with  /F fname
  9. ;          1.11    bios read signals Dos File End
  10. ;          1.2     conin translates Csr keys to WS
  11. ;                  time functon and blink attribute
  12. ;          zsim12 uploaded to simtel
  13. ;          1.21    Option /Snnn to restrain ramdisc size
  14. ;          1.22    look first for `COMSPEC` then \COMMAND.COM
  15. ;                  free 128K mem for OS-Shell
  16. ;                  some bug fixes
  17. ;                  do not save cpm_drv to disc parameter file anymore
  18. ;          1.3     can be assembled with option to make an interrupt
  19. ;                  request with every timer tick
  20. ;          1.4     user bios call for file transfer to/from msdos
  21. ;                  menu option reset screen
  22. ;          1.5     select drive 0 after warm boot from ctrl-brk-menu
  23. ;                  menu option swap drives
  24. ;                  no longer swap to root dir at os shell
  25. ;          1.6     IOBYTE support:
  26. ;                    function 6 and 7 can be set to the serial port
  27. ;          1.7     option /D to set physical drive
  28. ;                  option /H to get option help
  29. ;          2.0     Z80 emulation is now 20% faster
  30. ;          zsim20 uploaded to simtel
  31. ;          2.1     harddisc file C:
  32. ;                  work with only one disk drive no longer supported
  33. ;          2.2     option /A to start with A: as ramdisc
  34. ;                  option /N to start with autologin disabled
  35. ;                  combined functions for low level read and write
  36. ;          2.21    took NOP as default opcode to execute at int 0
  37. ;                  as zsid enables ints at the go command
  38. ;                  stored path of swapfile at os-shell, as swapfile
  39. ;                  couldn't be reloaded if user changed directory
  40.  
  41. .286
  42.  
  43.  
  44. DEFAULT_IOBYTE EQU   10000001b ; lpt0,,,video
  45.  
  46. CVERSION equ '2.21' ; to display on screen
  47. CVERSNR  equ 22h    ; to return if requested
  48. CVERSDATE equ '14/06/93'
  49.  
  50. ; CHANGE THE FELLOWING TO THE PHYSICAL DISK
  51. ; YOU WANT TO USE FOR CPM
  52.  
  53. IFNDEF PHYS_DRV
  54.   PHYS_DRV EQU 0   ; phys number of pc drive to use as CP/M floppy
  55. ENDIF
  56.  
  57. IF PHYS_DRV GT 1
  58.    %OUT ERROR: PHYSICAL CP/M DRIVE SET TO ILLEGAL VALUE: VALID IS 0 OR 1
  59.    ERR
  60. ENDIF
  61.  
  62. HARD_DISC_TOO EQU -1
  63. HARD_DISC_SIZE EQU 8192  ; the maximal amount for CP/M 2.2 is 8 M
  64.  
  65. ; IF TIMER_INTS THEN
  66. ;    at every PC Timertick a z80 interrupt request is made
  67. ; (if default int mode 0 is set execute DATABUS_BTE,
  68. ;  elseif int mode 1 do a RST 38H
  69. ;  else (int mode 2) call word ptr [I_Reg shl 8 + (DATABUS_BTE shl 1) )
  70. ; (Z80 emulator defaults to interrupt DISabled, IM 0)
  71.  
  72. TIMER_INTS EQU 0
  73. DATABUS_BTE EQU 0H   ; NOP, as secure default
  74.  
  75. INCLUDE Z80EMU.INC
  76.  
  77. EXTRN crtout:near,crtin:near,crtinstat:near,reset_crt:near,sel_scr_page:near
  78. EXTRN cursor_off:near,cursor_on:near
  79.  
  80. PUBLIC prg_exit,bios88
  81.  
  82. PUBLIC breakflag
  83.  
  84.  
  85. %nosyms        ; keine symbols im listing
  86. warn           ; alle warnings an
  87.  
  88. DOSSEG   ; UNBEDINGT notwendig, da fuer Speicherverwaltung des Z80 Segments
  89.          ; und der Ramdisk Stacksegment als letztes kommen muss
  90.          ; auch mussen Stack- und Codesegment Klassen 'STACK' bzw.
  91.          ; 'CODE'bekommen
  92.  
  93. LOCALS   ; fuer locale Labels in Prozeduren
  94.  
  95. JUMPS    ; automatische Sprunglaengenanpassung
  96.  
  97. CALLZ macro label ; Call if zero
  98. local exit
  99.       jnz short exit
  100.       call label
  101. exit:
  102. endm
  103.  
  104. CALLNZ macro label ; Call if not zero
  105. local exit
  106.       jz   short exit
  107.       call label
  108. exit:
  109. endm
  110.  
  111. CALLC macro label ; Call if carry
  112. local exit
  113.       jnc  short exit
  114.       call label
  115. exit:
  116. endm
  117.  
  118. MOVZ macro targ,src ; move if zero
  119. local exit
  120.       jnz short exit
  121.       mov targ,src
  122. exit:
  123. endm
  124.  
  125. MOVNZ macro targ,src ; move if not zero
  126. local exit
  127.       jz short exit
  128.       mov targ,src
  129. exit:
  130. endm
  131.  
  132.  
  133. TSTNCLR MACRO FLAG    ; Z-> war nicht gesetzt
  134.         CMP FLAG,FALSE
  135.         MOV FLAG,FALSE
  136. ENDM
  137.  
  138.  
  139. ;
  140. ; segmente des emulators:
  141. ;
  142.  
  143. ; emulator_seg   : emulator und bios code
  144. ; emudata_seg    : emulator data und z80 bios code
  145. ; stack_seg      : emulator und bios stack
  146. ; z80cpu_seg     : Segment des emulierten z80, 64k, dummy at 0 (in z80seg_adr)
  147. ; ramdisc_seg    : ramdisc fuer cp/m
  148. ;
  149.  
  150.  
  151. include dos.inc         ; dos functionen
  152.  
  153. ;
  154. ; ******* KONSTANTEN ********
  155. ;
  156.  
  157. DEFAULT_DMA        EQU 80H
  158. RECORD_LEN         EQU 80H
  159.  
  160.  
  161.  
  162. ZBIOSLEN           equ (zbiosend-zbiosbeg)
  163. ZBIOSDISPL         equ (0ffffh-ZBIOSLEN) and 0ff00h
  164. ; dies bewirkt Start auf neuer Seite, damit Bios auf XX00 anfaengt
  165. ZBIOS              equ offset zbiosbeg+ZBIOSDISPL
  166.  
  167. CTRL_BREAK_INT EQU 1BH
  168.  
  169. ESC_KEY            EQU 27
  170.  
  171. EMU_SCR_PAGE EQU 0
  172. DOS_SCR_PAGE EQU 1
  173.  
  174. ; folgende Konstanten werden als Flags zur Addressberechnung
  175. ; im Sektorbuffer benoetigt
  176.  
  177. READ_OP            EQU 0
  178. WRITE_OP           EQU 0FFH
  179.  
  180.  
  181.  
  182.  
  183. BDOSLEN            equ 1600h     ; Laenge ccp+bdos cp/m 2.2
  184. BDOS_CHK_SUM       equ 2d88h     ; Checksumme ueber Bdos Copyright Meldung
  185.  
  186. SYS_FRST_SEC       EQU 28
  187.          ; erster absoluter Sektor, den Bdos auf SysSpuren belegt
  188.  
  189. SYS_SECS           EQU BDOSLEN/RECORD_LEN ; Anzahl Sektoren, die System belegt
  190.  
  191. TRACK_BUF_LEN      EQU 10*512
  192.  
  193. CPM_EOF            EQU 26
  194.  
  195.  
  196. RMD                equ 1   ; phys Number of ramdisk IN CP/M
  197. IF HARD_DISC_TOO
  198. HARD_DISC          equ 2   ; phys Number of harddisk IN CP/M
  199. ENDIF
  200.  
  201.  
  202.  
  203. PHYS_SEKLEN        equ 512
  204. NSECTS             equ    2
  205. IF HARD_DISC_TOO
  206. NDISKS             equ    3  ; last disk # +1
  207. ELSE
  208. NDISKS             equ    2  ; last disk # +1
  209. ENDIF
  210. BPS                equ    2
  211.  
  212. ; -------------------------------------
  213. ;
  214. ; emulator data segment
  215. ;
  216. ; --------------------------------------
  217.  
  218.  
  219. emudata_seg segment para public 'DATA'
  220.  
  221. include zbios.inc
  222.  
  223. dpb_cpc     dpb <SPTC,BSHC,BLMC,EXMC,DSMC,DRMC,AL0C,AL1C,CKSC,OFFC>
  224. dpb_dta     dpb <SPTD,BSHD,BLMD,EXMD,DSMD,DRMD,AL0D,AL1D,CKSD,OFFD>
  225. dpb_eig     dpb <SPTD,BSHD,BLMD,EXMD,DSMD,DRMD,AL0D,AL1D,CKSD,OFFD>
  226. dpb_cpm86SS dpb <SPT0,BSH0,BLM0,EXM0,DSM0,DRM0,AL00,AL10,CKS0,OFF0>
  227. dpb_cpm86DS dpb <SPT1,BSH1,BLM1,EXM1,DSM1,DRM1,AL01,AL11,CKS1,OFF1>
  228.  
  229. ramdisklen dw (?)
  230. lasttrack_rd db (?) ; 0..127  (512K)
  231.  
  232. PUNCH_BUF_SIZE  equ 64
  233. READER_BUF_SIZE equ 64
  234.  
  235. ld_rd_string db 27,'E',27,'H','Initializing ramdisc ...',13,10,10,0
  236. ld_hd_string db 'Initializing CP/M harddisc ...',0
  237. start_string db 27,'E',27,'Y',32+6,32+24,27,'p'
  238.              db 'ZSIM'
  239.              db 27,'Y',32+8,32+18
  240.              db 'THE Z80 / CP/M Emulator',27,'q'
  241.              db 27,'Y',32+10,32+18
  242.              db 'Free for personal use'
  243.              db 27,'Y',32+12,32+18
  244.              db 27,'p','USE AT YOUR OWN RISC !',27,'q'
  245.              db 27,'Y',32+15,32+18
  246.              db '(C) 1990,1993 by '
  247.              db 27,'Y',32+17,32+18
  248.              db 'Jürgen G. Weber'
  249.              db 27,'Y',32+18,32+18
  250.              db 'Wiesentalstraße 1'
  251.              db 27,'Y',32+19,32+18
  252.              db 'D-74523 Schwäbisch Hall'
  253.              db 27,'Y',32+20,32+18
  254.              db 'Federal Republic of Germany'
  255.              db 27,'Y',32+24,32+17,27,'p'
  256.              db 'Insert a CP/M disk into drive '
  257. drv_letter   db 'A'
  258.              db ': then press any key'
  259.              db 27,'q'
  260.              db 0
  261.  
  262.  
  263. help_str     db 13,10
  264.              db 'ZSIM version '
  265.              db CVERSION
  266.              db ' - Z80 EMULATOR + CP/M 80 BIOS'
  267.              db 13,10,10
  268.              db '(C) 1990,1992,1993 by Jürgen Weber',13,10,10
  269.              db 'Options:',13,10,10
  270.              db '/Dn   n=0,1    Use PC disc drive n',13,10
  271.              db '/F <parmfile>  Use disc parameter file <parmfile>',13,10
  272.              db '/H or /?       Get this help',13,10
  273.              db '/Snnn          Restrain ramdisc size to nnn K',13,10
  274.              db '/C             Create the harddisc file HARDDISC.CPM',13,10
  275.              db '/N             Start with autologin disabled',13,10
  276.              db '/A             Start with ramdisc=A:',13,10
  277.              db 0
  278.  
  279. help_str_end equ $
  280.  
  281. db 'ZSIM is copyrighted by Jürgen Weber but'
  282. db ' it looks for the fellowing string: '
  283.  
  284. bdos_str db '        COPYRIGHT (C) 1979, DIGITAL RESEARCH  '
  285. bdos_str_end equ this byte
  286.  
  287. cpmsys_fileName  db 'CPMSYS.CPM',0
  288. ramdisc_fname    db 'RAMDISC.CPM',0
  289. harddisc_fname   db 'HARDDISC.CPM',0
  290. punch_fileName   db 'PUNCH.CPM',0
  291. reader_fileName  db 'READER.CPM',0
  292. temp_fname       db 'EMUOVL.$$$',0
  293.  
  294. fmt_file_flg db FALSE
  295. new_hdsk_flg db FALSE
  296. fmt_file_name    db 80 dup (?)
  297. file_promt_str db 'Enter Disk Parameter filename: ',0
  298. file_promt_str_end equ $
  299.  
  300.  
  301. menutab label word
  302.  
  303.      dw m_esc
  304.  
  305.      dw m_continue
  306.      dw m_save_rd_quit
  307.      dw m_quit
  308.      dw m_save_rd
  309.      dw m_del_pf
  310.      dw m_init_rdr
  311.      dw m_shell
  312.      dw m_edit_disk_parm
  313.      dw m_save_d_parm
  314.      dw m_load_d_parm
  315.      dw m_login_disc
  316.      dw m_swap_drives
  317.      dw m_reset_scr
  318.      dw m_w_boot
  319.      dw m_info
  320.  
  321. MESSAGE_COUNT=($-menutab)/2 - 1 ; ESC has no entry string
  322.  
  323. ; remember to set on entry in menutab for every menu_str
  324. menu_strs    db '\Continue','|'
  325.              db 'Save \Ramdisc/Quit','|'
  326.              db '\Quit','|'
  327.              db '\Save Ramdisc','|'
  328.              db '\Delete Punch File','|'
  329.              db '\Init Reader','|'
  330.              db '\OS Shell','|'
  331.              db 'Disk \Parameters','|'
  332.              db 'Sa\ve Parameters','|'
  333.              db '\Load Parameters','|'
  334.              db 'Logi\n Disc','|'
  335.              db 'Swap Driv\es','|'
  336.              db 'Rese\t Screen','|'
  337.              db '\Warm Boot','|'
  338.              db '\About','|'
  339.              db 0
  340. menu_strs_end equ this byte
  341.  
  342. MESG_ESC equ 0
  343.  
  344. LONGEST_MESSAGE=20
  345.  
  346.  
  347. prg_ext_box_res  dw 0ffffh
  348.  
  349.  
  350. disk_err_txt db 'Disk Error '
  351. disk_err_num db 2 dup (?)
  352.              db 'H, Class '
  353. disk_err_cls db 2 dup (?)
  354.              db 'H. Press ESC|',0
  355. disk_err_txt_end equ this byte
  356.  
  357.  
  358. f_not_found_txt db 'File not found. Press ESC|',0
  359. f_not_found_txt_end equ this byte
  360.  
  361. no_mem_txt db 'Not enough memory to shell. Press ESC|',0
  362. no_mem_txt_end equ this byte
  363.  
  364. on_sign_string equ this byte
  365.                    db 27,'E',27,'H'
  366.                    db 'jgw 64K cp/m 80 bios ver '
  367.                    db CVERSION
  368.                    db ' --  '
  369.                    db CVERSDATE
  370.                    db '  (C) 1990,1993 by Jürgen G. Weber'
  371.                    db 13,10,10
  372.                    db 'BDOS: ',27,'j',0
  373. bad_format         db 13,10
  374.                    db 'Unknown disc format. Insert new disc into drive '
  375. drv_letter1        db 'A'
  376.                    db ': and press any key'
  377.                    db 13,10,0
  378. no_sys             db 13,10
  379.                    db 'Could not read System sectors. Insert'
  380.                    db ' new disc and press any key'
  381. cr_lf_txt          db 13,10,0
  382. control_c_txt      db '^C...',0
  383. reset_scr_txt      db 27,'@',0
  384.  
  385. mfulstr db 13,10,'Not enough memory',13,10
  386. mfsend equ this byte
  387.  
  388. illparm_str db 13,10,'Illegal Command Line Parameter',13,10
  389. illparm_strend equ this byte
  390.  
  391. illdriv_str db 13,10,'CP/M drive my not be current MS-Dos drive.',13,10
  392. illdriv_strend equ this byte
  393.  
  394. dma_txt db 13,10
  395.         db 'Fatal: DMA Boundary Crossing'
  396.         db 13,10
  397. dma_txt_end equ this byte
  398.  
  399. exit_str db 'Type EXIT to return to CP/M Emulator ...',13,10
  400. exit_str_end equ this byte
  401.  
  402.  
  403. exec_par_block equ this word
  404.        dw 0
  405.        dw offset exec_cmd_line
  406.        dw seg    exec_cmd_line
  407.        dd 0
  408.        dd 0
  409. exec_cmd_line equ this word
  410.        db ec_str_end-ec_str
  411. ec_str db ''
  412. ec_str_end equ this byte
  413.        db 13
  414.  
  415. exec_usr_flg db FALSE
  416.  
  417. exec_usr_lne equ $
  418. db 0
  419.  db '/C '
  420. usr_lne equ $
  421. db 80 dup (?)
  422.  
  423.  
  424. no_cc_str  db 13,10,'COMMAND.COM not found. Press ESC.',13,10
  425. no_cc_str_end equ this byte
  426.  
  427. exec_fname db '\COMMAND.COM',0
  428. comspec db 80 dup (?)
  429.  
  430. var_comspec db 'COMSPEC='
  431. var_comspec_len equ $-var_comspec
  432.  
  433. good_dpb_edit db (?)
  434. db 2 dup (?)
  435.  
  436. breakflag  db FALSE
  437.  
  438.  
  439.  
  440. old_int1b  dd (?)
  441. stackpoi   dw (?)
  442.  
  443. sp_save    dw (?)
  444. ss_save    dw (?)
  445.  
  446. z80seg_adr dw (?)
  447. rdseg_adr  dw (?)
  448. rdlen      dw (?)
  449. max_rd_size dw 1024   ; default auf maximal
  450. exec_mem_start dw (?)
  451.  
  452. default_dta dd (?)
  453. psp_adr    dw (?)
  454. prog_len   dw (?)
  455. mem_end    dw (?)
  456. ovl_base   dw (?)
  457. hd_drive_flag db (?)
  458. ms_current_drive db (?)
  459.  
  460. tmp_word        dw (?)
  461.  
  462. z80_pc             dw ?
  463. ccp_adr            dw ?
  464. bdos_adr           dw ?
  465. bios_adr           dw ?
  466.  
  467. month_tab db 31,28,31,30,31,30,31,31,30,31,30,31
  468.  
  469. ; flag, dass im Speicher noch ein nicht auf disk geschriebener
  470. ; nicht-dir Track ist
  471. write_flag         db FALSE
  472.  
  473. in_boot_flag       db FALSE
  474.  
  475. home_flag          db FALSE
  476. last_track_written db 0,0
  477. dirtrack           db 0,0
  478. r_track            db 0,0
  479. w_track            db 0,0
  480.  
  481. track              db 0,0
  482. sector             db 0,0
  483. last_track_read    db 0ffh  ; default unmoeglich, noch nicht gelesen
  484.  
  485. ms_phys_sec_len    db (?)
  486. pspt_last          db 9
  487. phys_tracks_last   db 40
  488. frstps_last        db 041h
  489. dirtr_last         db 2
  490. dpb_last           dw offset dpb_cpc
  491.  
  492. cpm86dd_flag       db FALSE
  493.  
  494. drv_swap_flag      db FALSE
  495.  
  496. ; ACHTUNG: die Reihenfolge der folgenden Vars nicht
  497. ;          verändern, da sie so ans Modula UP übergeben werden
  498.  
  499. cpmdrv_set_flg     db FALSE
  500. cpm_drive          db PHYS_DRV
  501. first_phys_sec     db 41h
  502. phys_tracks        db (?)
  503. phys_sec_pt        db (?)
  504. cpm_phys_sec_len   db 2
  505. autologin_flag     db TRUE
  506.  
  507. ; end Reihenfolge wichtig
  508.  
  509.  
  510. retry_count        db 5
  511. side               db 0
  512.  
  513. dmaad              dw ?          ;direct memory address
  514. diskno             db ?          ;disk number 0-15
  515.  
  516.  
  517. punch_buf_entries  dw (?)
  518. punch_buf_ptr      dw (?)
  519.  
  520. reader_empty_flag  db TRUE
  521. reader_buf_entries dw (?)
  522. reader_buf_ptr     dw (?)
  523. reader_file_pointer dw 0,0
  524.  
  525. new_dosfilespecflg db (?)
  526. openin_handle      dw 0
  527. openout_handle     dw (?)
  528. hd_handle          dw 0          ; default: none
  529. dosfilespec        db 80 dup (?)
  530. temppath           db 'X:\'
  531.                    db 80 dup (?)
  532.  
  533. ; zeigt auf Bufferadresse des Tracks, der geschrieben werden soll
  534. outbuf_ptr         dw (?)
  535.  
  536. cpm_bdos_buf db BDOSLEN dup (?)
  537.  
  538. dirtrbuf db TRACK_BUF_LEN dup (?)
  539. secbuf   db TRACK_BUF_LEN dup (?)
  540. wrtbuf   db TRACK_BUF_LEN dup (?)
  541.  
  542. punch_buf  db PUNCH_BUF_SIZE dup (?)
  543. reader_buf db READER_BUF_SIZE dup (?)
  544.  
  545. ; dass die Buffer in der EXE-Datei erscheinen, laesst sich
  546. ; durch die Verwendung einer Gruppe mit den Buffern als
  547. ; Extra Segment umgehen
  548. ; jedoch muss dann bei jedem offset der Gruppenname angegeben werden
  549.  
  550. emudata_seg ends
  551.  
  552. ; ------------------------
  553.  
  554. DATA segment para public 'DATA'
  555.      ; Dummysegment zur Kombinierung mit Modula 2
  556. DATA ends
  557.  
  558. STACK_SIZE EQU 1000H
  559.  
  560. stack_seg  segment para stack 'STACK'
  561.       dw STACK_SIZE dup (?)            ; Stack ist recht gross
  562.                                   ; wegen Modula 2 UPs
  563. stack_seg  ends
  564.  
  565. z80cpu_seg segment at 0 ; dummy
  566. z80cpu_seg ends
  567.  
  568. ; -------------------------------------
  569. ; emulator und bios segment start
  570. ; -------------------------------------
  571.  
  572. invalidate_rdbuf macro
  573.        mov  last_track_read,0ffh
  574. endm
  575.  
  576. emulator_seg segment para public 'CODE'
  577.  
  578. assume  cs:emulator_seg,ds:emudata_seg,es:z80cpu_seg,ss:stack_seg
  579.  
  580. m2_ds  dw (?)                          ; fmodula routinen erwarten
  581.                                        ; bei cs:0 ihr DS
  582.  
  583. init proc                              ; emulator start
  584.  
  585.        mov  ax,emudata_seg
  586.  
  587.        mov  ds,ax            ; damit Vars angesprochen werden koennen
  588.  
  589.        mov  stackpoi,sp
  590.  
  591.        mov bx,ss             ; finde Programmende
  592.        mov ax,sp
  593.        mov cl,4
  594.        shr ax,cl             ; ax:=4
  595.        add bx,ax             ; bx=>programm ende
  596.        inc bx                ; vorsichtshalber
  597.  
  598.        push bx
  599.        mov  ax,es            ; es:0 => PSP
  600.        mov  psp_adr,ax
  601.        mov  bx,ax
  602.  
  603.        mov si,0
  604.        mov ax,[es:si+2]      ; ax=> mem end
  605.        mov  mem_end,ax
  606.        push ax
  607.        sub  ax,2000h
  608.        mov  ovl_base,ax
  609.        pop  ax
  610.        push ax
  611.        sub  ax,bx            ; mem end - prg start
  612.        mov  prog_len,ax
  613.        pop  ax               ; mem end
  614.        pop  bx               ; prg end
  615.  
  616.  
  617.        sub ax,bx             ; ax:=free mem
  618.        mov  z80seg_adr,bx
  619.  
  620.        mov  cx,1000h     ; = (10000h / 16) = 64K in Paragraphs
  621.        add  bx,cx
  622.  
  623.        mov  rdseg_adr,bx
  624.  
  625.        sub  ax,cx
  626.        jc   @@memful
  627.  
  628.        mov  ramdisklen,ax
  629.  
  630.        PUSHR <es,bx>
  631.        DOS GET_DTA
  632.        mov word ptr default_dta,bx
  633.        mov bx,es
  634.        mov word ptr default_dta+2,bx
  635.        POPR <bx,es>
  636.  
  637.        call parse_cmd_line
  638.        mov dx,offset illparm_str
  639.        mov cx,illparm_strend-illparm_str
  640.        jc short abort              ; Fehler: falscher Parameter
  641.  
  642.  
  643.        DOS  GET_DISK_DRIVE
  644.        mov  ms_current_drive,al
  645.        cmp  al,cpm_drive
  646.        mov dx,offset illdriv_str
  647.        mov cx,illdriv_strend-illdriv_str
  648.        je short abort              ; error: dosdrive equals cp/m drive
  649.  
  650.        mov  bx,offset ld_rd_string
  651.        call puts
  652.  
  653.        call init_ramdisc
  654.  
  655.        mov  bx,offset ld_hd_string
  656.        call puts
  657.  
  658.        call init_harddisc
  659.  
  660.        mov al,cpm_drive
  661.        add al,'A'
  662.        mov drv_letter,al
  663.        mov drv_letter1,al
  664.  
  665.  
  666.        mov  bx,offset start_string
  667.        call puts
  668.        call crtin            ; wait for keypressed
  669.  
  670.        call patch_int
  671.  
  672.        mov  ax,z80seg_adr
  673.        call clearz80         ; loesche z80 mem
  674.  
  675.        call patch_box
  676.  
  677. ; physikalische Sektorlaenge merken
  678.  
  679.       push es
  680.       mov  ax,0
  681.       mov  es,ax
  682.       les  di,[es:78h]
  683.       mov  al,es:[di+3]
  684.       pop  es
  685.       mov  ms_phys_sec_len,al
  686.  
  687.  
  688. ;
  689. ; offset z80 bios start merken
  690. ;
  691.        mov bios_adr,ZBIOSDISPL          ; bios Sprungleiste einrichten
  692.  
  693.        call z80ini                      ; reset z80 cpu
  694.  
  695.        mov ax,z80seg_adr
  696.        mov es,ax
  697.        mov ds,ax
  698. ;
  699. ; weiter mit cp/m cold boot
  700. ;
  701.        mov al,0
  702.        jmp bios88
  703.  
  704.  
  705. @@memful:
  706.        mov cx,mfsend-mfulstr
  707.        mov dx,offset mfulstr
  708. abort:
  709.        mov bx,STDERR
  710.        DOS WRITE_TO_HANDLE
  711.        mov al,1
  712.        DOS TERMINATE_EXE
  713. init   endp
  714.  
  715. get_comspec proc
  716. ; on entry: ds->psp
  717. ; si=seg data !
  718.  
  719.         PUSHR <ds,es,si,di>
  720.         mov ax,[ds:2ch]
  721.         mov ds,ax
  722.         mov es,si
  723.         mov bx,0
  724. @@loop:
  725.         mov si,bx
  726.         inc bx
  727.         mov di,offset var_comspec
  728.         mov cx,var_comspec_len
  729.         repz cmpsb
  730.         jcxz short @@found
  731.         cmp word ptr [ds:si-1],0
  732.         jnz @@loop
  733. @@exit:
  734.         POPR <di,si,es,ds>
  735.        ret
  736. @@found:
  737.         mov di,offset comspec
  738.         call strcpy
  739.         jmp @@exit
  740. get_comspec endp
  741.  
  742. get_startup_path proc
  743. get_startup_path endp
  744.  
  745.  
  746. parse_cmd_line proc
  747. LOCAL  dsseg:WORD = AUTO_SIZE
  748.        push bp
  749.        mov  bp,sp
  750.        sub  sp,AUTO_SIZE
  751.        PUSHR <ax,bx,cx,di,si,ds,es>
  752.  
  753.  
  754.         mov fmt_file_flg,FALSE
  755.         mov ax,ds
  756.         mov dsseg,ds
  757.         mov si,ax
  758.         mov es,ax             ; es:=prog vars
  759.         mov ax,psp_adr
  760.         mov ds,ax
  761.  
  762.         call get_comspec
  763.  
  764.         mov di,offset fmt_file_name
  765.         mov si,80h            ; si => Kommandozeilenparam
  766.         lodsb                 ; count
  767.         mov bh,0
  768.         mov bl,al
  769.         mov [si+bx],bh        ; 0
  770.         or  al,al
  771.         mov al,FALSE
  772.         jz  @@parm_done
  773. @@findslash:
  774. ; don't forget string help_str
  775.         lodsb
  776.         or al,al
  777.         jz  @@parm_done
  778.         cmp al," "
  779.         jz short @@findslash     ; +DEC CX
  780.         cmp al,"/"
  781.         jz  short @@good_sep
  782.         cmp al,"-"
  783.         jnz @@parm_err
  784. @@good_sep:
  785.         lodsb
  786.         cmp al,'?'
  787.         jz helpnabort
  788.         and al,not ('a'-'A')  ; toupper
  789.         cmp al,'H'
  790.         jz helpnabort
  791.  
  792.         cmp al,'C'
  793.         jnz short @@no_create
  794.         mov bx,offset new_hdsk_flg
  795.         mov byte ptr [es:bx],TRUE
  796.         jmp @@findslash
  797. @@no_create:
  798.         cmp al,'N'
  799.         jnz short @@no_no_autolog
  800.         mov bx,offset autologin_flag
  801.         mov byte ptr [es:bx],FALSE
  802.         jmp @@findslash
  803. @@no_no_autolog:
  804.         cmp al,'A'
  805.         jnz short @@no_swap
  806.         mov bx,offset drv_swap_flag
  807.         mov byte ptr [es:bx],TRUE
  808.         jmp @@findslash
  809. @@no_swap:
  810.         cmp al,'F'
  811.         jz  short @@parm_file
  812.         cmp al,'D'
  813.         jz  short @@phys_drive
  814.         cmp al,'S'
  815.         jnz @@parm_err
  816.  
  817.         call @@parse_num
  818.         cmp ax,640
  819.         ja @@parm_err
  820.         cmp ax,64
  821.         jb short @@parm_err
  822.         mov bx,offset max_rd_size
  823.         mov [es:bx],ax
  824.         jmp @@findslash
  825. @@parm_file:
  826.         mov di,offset fmt_file_name
  827. @@SKIP_BLN:
  828.         lodsb
  829.         cmp al," "
  830.         jz @@SKIP_BLN; +DEC CX
  831.         stosb         ; 1. non-blank
  832. @@cp_loop:
  833.         lodsb
  834.         stosb
  835.         or al,al
  836.         jz  short @@name_done
  837.         cmp al,' '
  838.         jz  short @@name_done
  839.         cmp al,13
  840.         jz  short @@name_done
  841.         jmp @@cp_loop
  842. @@name_done:
  843.         dec si
  844.         mov al,0
  845.         stosb         ; Filename Endzeichen
  846.         mov di,offset fmt_file_flg
  847.         mov byte ptr es:[di],TRUE
  848.         jmp @@findslash
  849. @@phys_drive:
  850.         lodsb
  851.         cmp al," "
  852.         jz @@phys_drive ; +DEC CX
  853.         sub al,'0'
  854.         jc short @@parm_err
  855.         cmp al,1
  856.         ja short @@parm_err
  857.         push ds
  858.         mov  ds,dsseg
  859.         mov  cpm_drive,al
  860.         mov  cpmdrv_set_flg,TRUE
  861.         pop  ds
  862.         jmp @@findslash
  863.  
  864. @@parse_num:
  865.         mov bx,10
  866.         mov ax,0
  867.         mov dh,0
  868. @@addloop:
  869.         mov dl,[si]
  870.         or dl,dl
  871.         jz  short @@done
  872.         inc si
  873.         sub dl,'0'
  874.         jc short @@done
  875.         cmp dl,9
  876.         ja short @@done
  877.         push dx
  878.         mul bx
  879.         pop dx
  880.         add ax,dx
  881.         jmp short @@addloop
  882. @@done:
  883.         ret
  884.  
  885. @@parm_done:
  886.        POPR <es,ds,si,di,cx,bx,ax>
  887.        clc
  888.        add  sp,AUTO_SIZE
  889.        pop bp
  890.        ret
  891. @@parm_err:
  892.        POPR <es,ds,si,di,cx,bx,ax>
  893.        stc
  894.        add  sp,AUTO_SIZE
  895.        pop bp
  896.        ret
  897. parse_cmd_line endp
  898.  
  899. helpnabort proc
  900.        mov  ax,emudata_seg
  901.        mov  ds,ax
  902.        mov cx,help_str_end-help_str
  903.        mov dx,offset help_str
  904.        jmp abort
  905. helpnabort endp
  906.  
  907. tst_hd_drive proc
  908.        PUSHR <ax,dx>
  909.        mov hd_drive_flag,FALSE
  910.        mov dl,cpm_drive
  911.        mov ah,15h                 ; Laufwerktyp ?
  912.        int 13h
  913.        jc  short @@exit           ; PC,XT
  914.        cmp ah,2                   ; erkennt DiskWechsel
  915.        jnz short @@exit
  916.        mov hd_drive_flag,TRUE
  917. @@exit:
  918.        POPR <dx,ax>
  919.        ret
  920. tst_hd_drive endp
  921.  
  922. ;
  923. ; der Interupt 1bH (Control-Break Interupt) muß auf eine Routine
  924. ; gelegt werden, die ein Abbruch Flag setzt
  925. ; Dieses wird dann bei jedem Bios Aufruf ausgewertet
  926. ;
  927. patch_int proc
  928.        PUSHR <ds,es,ax,bx,dx>
  929.        mov al,CTRL_BREAK_INT
  930.        DOS GET_VECTOR
  931.        mov word ptr old_int1b,bx
  932.        mov bx,es
  933.        mov word ptr old_int1b+2,bx
  934.        mov  dx,offset new_int1b
  935.        push cs
  936.        pop  ds
  937.        mov al,CTRL_BREAK_INT
  938.        DOS SET_VECTOR
  939. if TIMER_INTS
  940.        mov al,1cH  ; timer
  941.        DOS GET_VECTOR
  942.        mov word ptr cs:old_int1C,bx
  943.        mov bx,es
  944.        mov word ptr cs:old_int1C+2,bx
  945.        mov  dx,offset new_int1C
  946.        push cs
  947.        pop  ds
  948.        mov al,1cH
  949.        DOS SET_VECTOR
  950. endif
  951.        POPR <dx,bx,ax,es,ds>
  952.        ret
  953. patch_int endp
  954.  
  955. restore_int proc
  956.        push ds
  957.        lds dx,old_int1b
  958.        mov al,CTRL_BREAK_INT
  959.        DOS SET_VECTOR
  960. if TIMER_INTS
  961.        lds dx,cs:old_int1C
  962.        mov al,1Ch
  963.        DOS SET_VECTOR
  964. endif
  965.        pop ds
  966.        ret
  967. restore_int endp
  968.  
  969. new_int1b proc
  970.        push ax
  971.        push ds
  972.        mov  ax,emudata_seg
  973.        mov  ds,ax
  974.        cmp byte ptr cs:in_emu_flg,TRUE
  975.        jnz short @@not_in_emu
  976.        call ctrl_break_req
  977.        jmp short @@exit
  978. @@not_in_emu:
  979.        mov  breakflag,TRUE   ; nur wenn gerade bios code abgearbeitet wird
  980. @@exit:
  981.        pop  ds
  982.        pop  ax
  983.        iret
  984. new_int1b endp
  985.  
  986. if TIMER_INTS
  987.  
  988. old_int1C  dd (?)
  989.  
  990. ; at every timer tick do an interrupt request
  991.  
  992. new_int1C proc
  993.        cmp byte ptr cs:in_emu_flg,TRUE
  994.        push ax
  995.        mov al,DATABUS_BTE
  996.        CALLZ interrupt_request    ; only if Z80 is running
  997.        pop ax
  998.        jmp dword ptr cs:[old_int1C]
  999. new_int1C endp
  1000.  
  1001. endif ; TIMER_INTS
  1002.  
  1003. ; wird auch von Z80EMU.OP76 HALT aufgerufen
  1004.  
  1005. prg_exit proc FAR
  1006.        PUSHR <ds,es,ax>
  1007.        PUSHR <bx,cx,dx,si>
  1008.        mov  ax,emudata_seg
  1009.        mov  ds,ax
  1010.        mov  ax,z80seg_adr
  1011.        mov  es,ax
  1012.        call restore_int
  1013.        mov  breakflag,FALSE
  1014.  
  1015.        call wrt_out_punch
  1016.  
  1017.        mov  cx,menu_strs_end-menu_strs   ; high(messages)
  1018.        mov  si,offset menu_strs          ; offs(messages)
  1019.  
  1020.        call box_call
  1021.        sal ax,1
  1022.        mov di,ax
  1023.        call menutab[di]
  1024.  
  1025.        call patch_int
  1026.        POPR <si,dx,cx,bx>
  1027.        POPR <ax,es,ds>
  1028.        ret
  1029. prg_exit endp
  1030.  
  1031.  
  1032. ; Menü durch ESC abgebrochen
  1033. m_esc proc
  1034.        ret
  1035. m_esc endp
  1036.  
  1037. ; Menüpunkt Emulation fortfahren
  1038. m_continue proc
  1039.       ret
  1040. m_continue endp
  1041.  
  1042. ; Menüpunkt Quit
  1043. m_quit proc
  1044. ; etwaige Zeichen im Punch Buffer noch ausschreiben
  1045.        call wrt_out_punch
  1046.  
  1047.        mov cl,31                  ; GotoXY(1,25)
  1048.        call crtout
  1049.        mov cl,1
  1050.        call crtout
  1051.        mov cl,25
  1052.        call crtout
  1053.        mov  al,0
  1054. ABORT_EMU:
  1055.        DOS TERMINATE_EXE
  1056. m_quit endp
  1057.  
  1058. ; Menüpunkt Ramdisk speichern
  1059. m_save_rd proc
  1060.       call save_ramdisc
  1061.       ret
  1062. m_save_rd endp
  1063.  
  1064. ; Menüpunkt Ramdisk speichern + Quit
  1065. m_save_rd_quit proc
  1066.        call save_ramdisc
  1067.        jmp short m_quit
  1068. m_save_rd_quit endp
  1069.  
  1070. ; Menüpunkt Punch buffer file löschen
  1071. m_del_pf proc
  1072.      call del_punch_file
  1073.      ret
  1074. m_del_pf endp
  1075. ; Menüpunkt Reader initialisieren
  1076. m_init_rdr proc
  1077.       call reset_reader_buf
  1078.       ret
  1079. m_init_rdr endp
  1080.  
  1081. ; Menüpunkt OS Shell
  1082. m_shell proc
  1083.        call dos_shell
  1084.        ret
  1085. m_shell endp
  1086.  
  1087. update_disk_pars proc
  1088.       PUSHR <AX,BX>
  1089.        mov  cpm86dd_flag,FALSE
  1090.        mov  ah,0
  1091.        mov  al,dpb0.off-dpb0.spt  ; off
  1092.        call get_dpb_entrie        ; nach bx
  1093.        mov  dirtrack,bl
  1094.       POPR <BX,AX>
  1095.       ret
  1096. update_disk_pars endp
  1097.  
  1098. ; Menüpunkt Diskettenparameter editieren
  1099. m_edit_disk_parm proc
  1100.        call edit_disk_pars
  1101.        cmp  good_dpb_edit,1
  1102.        jnz  short @@exit
  1103.        call update_disk_pars
  1104.  
  1105.        cmp  in_boot_flag,TRUE
  1106.        jz   short @@exit          ; mit boot weitermachen
  1107.        call m_w_boot
  1108. @@exit:
  1109.        ret
  1110. m_edit_disk_parm endp
  1111.  
  1112. prepare_fname proc
  1113.        mov  di,offset fmt_file_name
  1114.        push di
  1115.        mov  cx,80
  1116.        mov  si,offset file_promt_str
  1117.        mov  bx,file_promt_str_end-file_promt_str
  1118.        call input_string
  1119.        pop  bx
  1120.        or   byte ptr [bx],0          ; Test ob was eingegeben, nein => Z
  1121.        ret
  1122. prepare_fname endp
  1123.  
  1124. ; Menüpunkt Diskettenparameter speichern
  1125. m_save_d_parm proc
  1126.        call prepare_fname
  1127.        jz short @@exit
  1128.        call save_disk_pars
  1129. @@exit:
  1130.        ret
  1131. m_save_d_parm endp
  1132.  
  1133. ; Menüpunkt Diskettenparameter laden
  1134. m_load_d_parm proc
  1135.        call prepare_fname
  1136.        jz short @@exit
  1137.        call load_disk_pars
  1138.        jmp  short m_w_boot
  1139. @@exit:
  1140.        ret
  1141. m_load_d_parm endp
  1142.  
  1143. ; Menüpunkt CP/M warm boot durchführen
  1144. m_w_boot proc
  1145.        mov sp,stackpoi
  1146.        call patch_int
  1147.        mov ax,z80seg_adr
  1148.        mov es,ax
  1149.        mov di,CDISK
  1150.        and byte ptr es:[di],11b   ; select sensible disk
  1151.        call init_iobyte
  1152.        mov al,1
  1153.        jmp bios88
  1154. m_w_boot endp
  1155.  
  1156. m_login_disc proc
  1157.        push word ptr autologin_flag
  1158.        mov  autologin_flag,TRUE
  1159.        call login_disc
  1160.        invalidate_rdbuf
  1161.        pop  word ptr autologin_flag
  1162.        ret
  1163. m_login_disc endp
  1164.  
  1165. ; Menüpunkt About Author
  1166. m_info proc
  1167.        call about_author
  1168.        ret
  1169. m_info endp
  1170.  
  1171. m_swap_drives proc
  1172.         cmp drv_swap_flag,TRUE
  1173.         mov drv_swap_flag,FALSE
  1174.         jz short @@is_true
  1175.         mov drv_swap_flag,TRUE
  1176. @@is_true:
  1177.        jmp  short m_w_boot
  1178. m_swap_drives endp
  1179.  
  1180. ; Menüpunkt Reset Screen
  1181. m_reset_scr proc
  1182.         mov bx,offset reset_scr_txt
  1183.         call puts
  1184.         ret
  1185. m_reset_scr endp
  1186.  
  1187.  
  1188. ; Fehler durch Ueberschreiten der DMA Segment Grenze
  1189. ; siehe c't 4/90 S.412
  1190.  
  1191. dma_bound proc
  1192.        mov bx,STDERR
  1193.        mov cx,dma_txt_end-dma_txt
  1194.        mov dx,offset dma_txt
  1195.        DOS WRITE_TO_HANDLE
  1196.        mov al,1
  1197.        jmp ABORT_EMU
  1198. dma_bound endp
  1199.  
  1200. disp_disk_err proc
  1201.        pushf                      ; cy aufheben
  1202.        PUSHR <si,cx,dx,bx>
  1203.         PUSHR <DI,BP,ES,DS>
  1204.         DOS GET_EXTENDED_ERRORS
  1205.         POPR <DS,ES,BP,DI>
  1206.         mov  bx,offset disk_err_num
  1207.         call hexbyte
  1208.         mov  al,bh
  1209.         mov  bx,offset disk_err_cls
  1210.         call hexbyte
  1211.        mov si,offset disk_err_txt
  1212.        mov cx,disk_err_txt_end-disk_err_txt
  1213.        call box_call
  1214.        POPR <bx,dx,cx,si>
  1215.        popf
  1216.        ret
  1217. disp_disk_err endp
  1218.  
  1219. disp_f_not_found proc
  1220.        pushf                      ; cy aufheben
  1221.        PUSHR <si,cx>
  1222.        mov si,offset f_not_found_txt
  1223.        mov cx,f_not_found_txt_end-f_not_found_txt
  1224.        call box_call
  1225.        POPR <cx,si>
  1226.        popf
  1227.        ret
  1228. disp_f_not_found endp
  1229.  
  1230. disp_no_mem proc
  1231.        PUSHR <si,cx>
  1232.        mov si,offset no_mem_txt
  1233.        mov cx,no_mem_txt_end-no_mem_txt
  1234.        call box_call
  1235.        POPR <cx,si>
  1236.        ret
  1237. disp_no_mem endp
  1238.  
  1239.  
  1240. hexbyte    PROC
  1241. ; in: bx-> store for hexbyte
  1242. ;     al=hexbyte
  1243.           push ax
  1244.           shr al,1                   ;extract high nibble
  1245.           shr al,1
  1246.           shr al,1
  1247.           shr al,1
  1248.           call nib
  1249.           pop ax
  1250.           and al,0fh
  1251. nib:
  1252.           add al,90h                 ;special hex conversion sequence
  1253.           daa                        ;using ADDs and DAA's
  1254.           adc al,40h
  1255.           daa                        ;nibble now converted to ASCII
  1256.           mov [bx],al
  1257.           inc bx
  1258.           ret
  1259. hexbyte ENDP
  1260.  
  1261.  
  1262. EXTRN EmuMenu_DoMenue:far,EmuMenu_EditDPB:far
  1263. EXTRN EmuMenu_InputString:far,EmuMenu_About:far,EmuMenu_init:far
  1264.  
  1265. ; fmodula2 laedt merkwuerdigerweise am Anfang DS aus CS:0
  1266. ; also muss man dort ds hinbringen
  1267. ; Trotzdem sollte vor Aufruf einer Funktion DS richtig
  1268. ; geladen sein.
  1269.  
  1270. patch_box proc
  1271.        mov  ax,DATA
  1272.        mov  [cs:0],ax
  1273.        ret
  1274. patch_box endp
  1275.  
  1276. box_call proc                     ; um Modula 2 UPs aufzurufen
  1277. ;
  1278. ; in:  ds:si => menuetext
  1279. ;      cx    =  len(menuetext)
  1280. ; out: ax = result
  1281. ;
  1282. ; auf dem STACK muss GENUG FREI sein, um zu erzeugendes WINDOW
  1283. ; ABZUSPEICHERN
  1284. ;
  1285. COMMENT @
  1286.  
  1287. DEFINITION MODULE EmuM2;
  1288.  
  1289. FROM SYSTEM IMPORT BYTE,WORD;
  1290.  
  1291. TYPE PhysDiskPars = RECORD
  1292.            cpm_drive       : BYTE;
  1293.            first_phys_sec  : BYTE;
  1294.            phys_tracks     : BYTE;
  1295.            phys_sec_pt     : BYTE;
  1296.            bytes_per_sec   : BYTE;
  1297.            autologin_flag  : BYTE;
  1298.        END;
  1299.  
  1300. dpb = RECORD
  1301.              spt  : WORD;
  1302.              bsh  : BYTE;
  1303.              blm  : BYTE;
  1304.              exm  : BYTE;
  1305.              dsm  : WORD;
  1306.              drm  : WORD;
  1307.              al0  : BYTE;
  1308.              al1  : BYTE;
  1309.              cks  : WORD;
  1310.              off  : WORD;
  1311.            END;
  1312.      DPBPtr = POINTER TO dpb;
  1313.      PDPPtr = POINTER TO PhysDiskPars;
  1314.  
  1315.  
  1316. PROCEDURE DoMenue(x,y:CARDINAL;messages:ARRAY OF CHAR;
  1317.                   VAR WinSave:ARRAY OF CHAR;VAR res:CARDINAL);
  1318. (* Pop Up Menue, obere linke Ecke des Rahmens bei x,y.
  1319.    messages = String mit darzustellenden Menuepunkten; Stringende = 0C.
  1320.    Menuepunkte werden durch | getrennt, auch nach letztem Menuepunkt
  1321.    MUSS | stehen.
  1322.    Jeder Menuepunkt darf durch Druecken eines einzigen Zeichens angewaehlt
  1323.    werden, das hell dargestellt wird. Diesem Zeichen muss der Backslash \
  1324.    vorangestellt werden.
  1325.    Es duerfen maximal 20 Menuepunkte sein.
  1326.    WinSave muss genug Platz enthalten, um Hintergrund + dessen Attribute
  1327.    abzuspeichern, = (Laengster Menuepunkt+2)*2*(Menuepunkte+2)
  1328. *)
  1329.  
  1330. PROCEDURE EditDPB(p:DPBPtr;q:PDPPtr;
  1331.                   VAR WinSave:ARRAY OF CHAR;VAR OK:BOOLEAN);
  1332. (* Len WinSave=20*18*2=720 *)
  1333.  
  1334. PROCEDURE InputString(VAR WinSave,s,p:ARRAY OF CHAR);
  1335. (* Es wird vorrausgesetzt, daß prompt p < 30 und string s < 30 *)
  1336.  
  1337.  
  1338. PROCEDURE About(VAR WinSave:ARRAY OF CHAR);
  1339. (* Author ausgeben *)
  1340.  
  1341.  
  1342. END EmuM2.
  1343.  
  1344.  
  1345. @
  1346.  
  1347. HIGH_WinSave=(LONGEST_MESSAGE+2)*2*(MESSAGE_COUNT+2)
  1348.  
  1349. IF HIGH_WinSave gt 2*STACK_SIZE/3
  1350.    %out WARNING: POPUP WINDOW REQUIRES MUCH OF STACK
  1351. ENDIF
  1352.  
  1353.        PUSHR <bx,cx,dx,di,si,bp,ds,es>
  1354.        sub  sp,HIGH_WinSave
  1355.        mov  bx,sp
  1356.        mov  ax,20
  1357.        push ax                 ; x
  1358.        mov  ax,7
  1359.        push ax                 ; y
  1360.        push cx                 ; high(messages)
  1361.        push ds                 ; seg(messages)
  1362.        push si                 ; offs(messages)
  1363.        mov  cx,HIGH_WinSave
  1364.        push cx                 ; high(WinSave)
  1365.        push ss                 ; seg(WinSave)
  1366.        push bx                 ; offs(WinSave)
  1367.        mov  ax,seg prg_ext_box_res
  1368.        push ax                 ; seg(prg_ext_box_res)
  1369.        mov  ax,offset prg_ext_box_res
  1370.        push ax                 ; offs(prg_ext_box_res)
  1371. ;box_adr equ this byte
  1372.        mov  ax,DATA
  1373.        mov  ds,ax
  1374.        call EmuMenu_DoMenue
  1375.        add  sp,HIGH_WinSave
  1376.        POPR <es,ds>
  1377.        mov  ax,prg_ext_box_res
  1378.        POPR <bp,si,di,dx,cx,bx>
  1379.        ret
  1380. box_call endp
  1381.  
  1382.  
  1383. edit_disk_pars proc
  1384.  
  1385. HIGH_WinSave=800
  1386.  
  1387. IF HIGH_WinSave gt 2*STACK_SIZE/3
  1388.    %out WARNING: POPUP WINDOW REQUIRES MUCH OF STACK
  1389. ENDIF
  1390.        PUSHR <bx,cx,dx,di,si,bp,ds,es>
  1391.        sub  sp,HIGH_WinSave
  1392.        mov  bx,sp
  1393.        mov  ax,z80seg_adr
  1394.        push ax                 ; seg(p)  p:DPBPtr
  1395.        mov  ax,offset dpb0+ZBIOSDISPL
  1396.        push ax                 ; offs(p)
  1397.        mov  ax,seg cpm_drive
  1398.        push ax                 ; seg (q) q:PDPPtr;
  1399.        mov  ax,offset cpm_drive
  1400.        push ax                 ; offs (q)
  1401.        mov  cx,HIGH_WinSave
  1402.        push cx                 ; high(WinSave)
  1403.        push ss                 ; seg(WinSave)
  1404.        push bx                 ; offs(WinSave)
  1405.        mov  ax,seg good_dpb_edit
  1406.        push ax                 ; seg(ok)
  1407.        mov  ax,offset good_dpb_edit
  1408.        push ax                 ; offs(ok)
  1409.        mov  ax,DATA
  1410.        mov  ds,ax
  1411.        call EmuMenu_EditDPB
  1412.        add  sp,HIGH_WinSave
  1413.        POPR <es,ds,bp,si,di,dx,cx,bx>
  1414.        ret
  1415. edit_disk_pars endp
  1416.  
  1417. ;PROCEDURE InputString(VAR WinSave,s,p:ARRAY OF CHAR);
  1418.  
  1419. input_string proc   ; ds:si = prompt, bx = len prompt
  1420.                     ; ds:di = string  cx = len string
  1421. LOCAL  prompt_str,lenpr,in_str,lenstr:WORD = AUTO_SIZE
  1422.        push bp
  1423.        mov  bp,sp
  1424.        sub  sp,AUTO_SIZE
  1425.        mov  prompt_str,si
  1426.        mov  in_str,di
  1427.        mov lenpr,bx
  1428.        mov lenstr,cx
  1429. HIGH_WinSave=800
  1430.  
  1431. IF HIGH_WinSave gt 2*STACK_SIZE/3
  1432.    %out WARNING: POPUP WINDOW REQUIRES MUCH OF STACK
  1433. ENDIF
  1434.        PUSHR <bx,cx,dx,di,si,bp,ds,es>
  1435.        sub  sp,HIGH_WinSave
  1436.        mov  bx,sp
  1437.        mov  ax,z80seg_adr
  1438.  
  1439.        mov  cx,HIGH_WinSave
  1440.        push cx                 ; high(WinSave)
  1441.        push ss                 ; seg(WinSave)
  1442.        push bx                 ; offs(WinSave)
  1443.  
  1444.        push lenstr             ; high(s)
  1445.        push ds                 ; seg(s)
  1446.        push in_str             ; offs(s)
  1447.        push lenpr              ; high(p)
  1448.        push ds                 ; seg(p)
  1449.        push prompt_str         ; offs(p)
  1450.        mov  ax,DATA
  1451.        mov  ds,ax
  1452.        call EmuMenu_InputString
  1453.        add  sp,HIGH_WinSave
  1454.        POPR <es,ds,bp,si,di,dx,cx,bx>
  1455.        mov  sp,bp
  1456.        pop  bp
  1457.        ret
  1458. input_string endp
  1459.  
  1460.  
  1461. load_disk_pars proc
  1462. LOCAL  handle:WORD = AUTO_SIZE
  1463.        push bp
  1464.        mov  bp,sp
  1465.        sub  sp,AUTO_SIZE
  1466.        call @@fopen
  1467.        jnc  short @@ok
  1468.        cmp  ax,2
  1469.        CALLZ disp_f_not_found
  1470.        jc  short @@exit           ; nicht da
  1471. @@ok:
  1472.        call @@fread
  1473.        call @@fclose
  1474.        call update_disk_pars
  1475.        mov  autologin_flag,FALSE
  1476. @@exit:
  1477.        mov  sp,bp
  1478.        pop  bp
  1479.        ret
  1480.  
  1481. @@fopen:
  1482.        mov al,0
  1483.        mov dx,offset fmt_file_name
  1484.        DOS OPEN_FILE
  1485.        mov handle,ax
  1486.        ret
  1487.  
  1488. @@fclose:
  1489.        mov bx,handle
  1490.        DOS CLOSE_FILE
  1491.        CALLC disp_disk_err
  1492.        ret
  1493.  
  1494. @@fread:
  1495.        mov dx,offset tmp_word
  1496.        mov bx,handle
  1497.        mov cx,2
  1498.        DOS READ_FROM_HANDLE
  1499.        CALLC disp_disk_err
  1500.        mov bx,dx
  1501.        mov bx,[bx]
  1502.        cmp bx,'WJ'
  1503.        jnz  short @@ldexit         ; falscher Kenncode <> 'JW'
  1504.  
  1505.        ; cp/m Parameter laden
  1506.  
  1507.        mov dx,offset offset dpb0+ZBIOSDISPL
  1508.        mov bx,handle
  1509.        mov cx,size dpb
  1510.        push ds
  1511.        mov ax,z80seg_adr
  1512.        mov ds,ax
  1513.        DOS READ_FROM_HANDLE
  1514.        pop ds
  1515.        CALLC disp_disk_err
  1516.  
  1517.        ; physikalische Parameter laden
  1518.  
  1519.        mov dx,offset first_phys_sec
  1520.        mov bx,handle
  1521.        mov cx,autologin_flag-first_phys_sec
  1522.        DOS READ_FROM_HANDLE
  1523.        CALLC disp_disk_err
  1524.  
  1525. @@ldexit:
  1526.      ret
  1527. load_disk_pars endp
  1528.  
  1529. save_disk_pars proc
  1530. LOCAL  handle:WORD = AUTO_SIZE
  1531.        push bp
  1532.        mov  bp,sp
  1533.        sub  sp,AUTO_SIZE
  1534.        call @@fopen
  1535.             jc short @@exit
  1536.        call @@fwrite
  1537.        call @@fclose
  1538. @@exit:
  1539.        mov  sp,bp
  1540.        pop  bp
  1541.        ret
  1542.  
  1543.  
  1544. @@fopen:
  1545.        mov cx,0
  1546.        mov dx,offset fmt_file_name
  1547.        DOS CREATE_FILE
  1548.        CALLC disp_disk_err
  1549.        mov handle,ax
  1550.        ret
  1551.  
  1552. @@fclose:
  1553.        mov bx,handle
  1554.        DOS CLOSE_FILE
  1555.        CALLC disp_disk_err
  1556.        ret
  1557.  
  1558. @@fwrite:
  1559.  
  1560. ; erst Kennung schreiben
  1561.  
  1562.        mov bx,offset tmp_word
  1563.        mov [bx],'WJ'
  1564.        mov dx,bx
  1565.        mov bx,handle
  1566.        mov cx,2
  1567.        DOS WRITE_TO_HANDLE
  1568.        CALLC disp_disk_err
  1569.  
  1570.       ; cp/m Parameter schreiben
  1571.  
  1572.        mov dx,offset offset dpb0+ZBIOSDISPL
  1573.        mov bx,handle
  1574.        mov cx,size dpb
  1575.        push ds
  1576.        mov ax,z80seg_adr
  1577.        mov ds,ax
  1578.        DOS WRITE_TO_HANDLE
  1579.        pop ds
  1580.        CALLC disp_disk_err
  1581.  
  1582.        ; physikalische Parameter schreiben
  1583.  
  1584.        mov dx,offset first_phys_sec
  1585.        mov bx,handle
  1586.        mov cx,autologin_flag-first_phys_sec
  1587.        DOS WRITE_TO_HANDLE
  1588.        CALLC disp_disk_err
  1589.  
  1590.      ret
  1591. save_disk_pars endp
  1592.  
  1593. about_author proc
  1594.        PUSHR <bx,cx,dx,di,si,bp,ds,es>
  1595.        sub  sp,HIGH_WinSave
  1596.        mov  bx,sp
  1597.        mov  cx,HIGH_WinSave
  1598.        push cx                 ; high(WinSave)
  1599.        push ss                 ; seg(WinSave)
  1600.        push bx                 ; offs(WinSave)
  1601.        mov  ax,DATA
  1602.        mov  ds,ax
  1603.        call EmuMenu_About
  1604.        add  sp,HIGH_WinSave
  1605.        POPR <es,ds,bp,si,di,dx,cx,bx>
  1606.        ret
  1607. about_author endp
  1608.  
  1609. clearz80 proc    ; loesche z80mem
  1610. ;
  1611. ; input: ax=seg z80 segment
  1612. ; alle  register ok
  1613. ;
  1614.        push es
  1615.        PUSHR <ax,cx,di>
  1616.        mov es,ax
  1617.        mov cx,8000h                      ; 32k words
  1618.        mov di,0
  1619.        mov ax,0
  1620.        rep stosw                         ; es:di := 0000h
  1621.        POPR <di,cx,ax>
  1622.        pop es
  1623.        ret
  1624. clearz80 endp
  1625.  
  1626. dos_exec proc
  1627.        cmp  exec_usr_flg,TRUE
  1628.        jz short @@cont1
  1629.        mov   al,DOS_SCR_PAGE
  1630.        call  sel_scr_page
  1631.        mov bx,STDOUT
  1632.        mov cx,exit_str_end-exit_str
  1633.        mov dx,offset exit_str
  1634.        DOS WRITE_TO_HANDLE
  1635. @@cont1:
  1636.        PUSHR <bx,cx,dx,di,si,bp,es>
  1637. ; first try calling `COMSPEC`
  1638.        mov   sp_save,sp
  1639.        mov   ss_save,ss
  1640.        mov   bx,seg    exec_par_block
  1641.        mov   es,bx
  1642.        mov   bx,offset exec_par_block
  1643.        mov   dx,offset comspec
  1644.        mov   ax,seg    comspec
  1645.        mov   ds,ax
  1646.        mov   al,0                 ; exec
  1647.        DOS   EXEC                 ; ax:=error code
  1648.        jnc short @@done
  1649. ; if that failed try \COMMAND.COM
  1650.        mov   bx,seg    exec_par_block
  1651.        mov   es,bx
  1652.        mov   bx,offset exec_par_block
  1653.        mov   dx,offset exec_fname
  1654.        mov   ax,seg    exec_fname
  1655.        mov   ds,ax
  1656.        mov   al,0                 ; exec
  1657.        DOS   EXEC                 ; ax:=error code
  1658. @@done:
  1659.        mov   bx,emudata_seg
  1660.        mov   ds,bx
  1661.        cli
  1662.        mov   ss,ss_save
  1663.        mov   sp,sp_save
  1664.        sti
  1665.        POPR  <es,bp,si,di,dx,cx,bx>
  1666.        cmp   ax,2             ; file not found
  1667.        jnz   short @@cc_found
  1668.        mov bx,STDERR
  1669.        mov cx,no_cc_str_end-no_cc_str
  1670.        mov dx,offset no_cc_str
  1671.        DOS WRITE_TO_HANDLE
  1672. @@press_esc:
  1673.        call crtin
  1674.        cmp  al,ESC_KEY
  1675.        jnz  short @@press_esc
  1676. @@cc_found:
  1677.        cmp  exec_usr_flg,TRUE
  1678.        mov   al,0
  1679.        CALLNZ  sel_scr_page
  1680.        ret
  1681. dos_exec endp
  1682.  
  1683.  
  1684. dos_shell proc
  1685. LOCAL  handle:WORD,mem_adr:WORD = AUTO_SIZE
  1686.        PUSHR <ax,bx,cx,dx,si,di>
  1687.        push bp
  1688.        mov  bp,sp
  1689.        sub  sp,AUTO_SIZE
  1690.  
  1691.        mov  ax,ovl_base
  1692.        sub  ax,z80seg_adr
  1693.        jnc  short @@memok
  1694.        call disp_no_mem
  1695.        jmp  short @@exit
  1696. @@memok:
  1697.        call @@fcreate
  1698.             jc short @@exit
  1699.        call @@fwrite
  1700.        call @@fclose
  1701.        call @@set_free
  1702.        call dos_exec
  1703.        call @@get_mem
  1704.        call @@fopen
  1705.        call @@fread
  1706.        call @@fclose
  1707.        mov dx,offset temppath
  1708.        DOS  DELETE_FILE
  1709.        CALLC disp_disk_err
  1710. @@exit:
  1711.        mov  sp,bp
  1712.        pop  bp
  1713.        POPR <di,si,dx,cx,bx,ax>
  1714.        ret
  1715.  
  1716. @@set_free:
  1717.        push es
  1718.        mov  es,psp_adr
  1719.        mov  bx,prog_len
  1720.        sub  bx,2000h
  1721.        DOS  MODIFY_MEMORY
  1722.        mov  bx,mem_end
  1723.        sub  bx,2000h
  1724.        mov  ovl_base,bx
  1725.        pop  es
  1726.        ret
  1727.  
  1728. @@get_mem:
  1729.        push es
  1730.        mov  es,psp_adr
  1731.        mov  bx,prog_len
  1732.        DOS  MODIFY_MEMORY
  1733.        pop  es
  1734.        ret
  1735.  
  1736. @@fcreate:
  1737.        DOS  GET_DISK_DRIVE
  1738.        add al,'A'
  1739.        mov byte ptr temppath,al
  1740.        mov dl,0   ; default drive
  1741.        mov si,(offset temppath) + 3
  1742.        DOS GET_DIRECTORY
  1743.        dec si
  1744.        push si
  1745. @@srch0:
  1746.        lodsb
  1747.        or al,al
  1748.        jnz short @@srch0
  1749.        sub si,2      ; si -> last char
  1750.        cmp byte ptr [si],'\'
  1751.        jz short @@root
  1752.        inc si
  1753.        mov byte ptr [si],'\'
  1754. @@root:
  1755.        inc si
  1756.        mov di,si
  1757.        push ds
  1758.        pop es
  1759.        mov si,offset temp_fname
  1760.        call strcpy
  1761.        pop dx   ; dx -> "\..\.."
  1762.        mov cx,2 ; Hidden
  1763.        DOS CREATE_FILE
  1764.        CALLC disp_disk_err        ; Abbruch nach Error in toplevel
  1765.        mov handle,ax
  1766.        ret
  1767.  
  1768. @@fopen:
  1769.        mov al,0
  1770.        mov dx,offset temppath
  1771.        DOS OPEN_FILE
  1772.        CALLC disp_disk_err
  1773.        mov handle,ax
  1774.        ret
  1775.  
  1776. @@fclose:
  1777.        mov bx,handle
  1778.        DOS CLOSE_FILE
  1779.        CALLC disp_disk_err
  1780.        ret
  1781.  
  1782. @@fwrite:
  1783.        push ds
  1784.        mov  si,ovl_base
  1785.        mov  cx,4               ; do 4*32K
  1786. @@wlp:
  1787.        push cx
  1788.        mov  bx,handle
  1789.        mov  cx,8000h
  1790.        mov  ds,si
  1791.        mov  dx,0
  1792.        DOS WRITE_TO_HANDLE
  1793.        CALLC disp_disk_err
  1794.        add  si,800h
  1795.        pop  cx
  1796.        loop @@wlp
  1797.        pop  ds
  1798.       ret
  1799. ; end fwrite
  1800. @@fread:
  1801.        push ds
  1802.        mov  si,ovl_base
  1803.        mov  cx,4               ; do 4*32K
  1804. @@rlp:
  1805.        push cx
  1806.        mov  bx,handle
  1807.        mov  cx,8000h
  1808.        mov  ds,si
  1809.        mov  dx,0
  1810.        DOS  READ_FROM_HANDLE
  1811.        CALLC disp_disk_err
  1812.        add  si,800h
  1813.        pop  cx
  1814.        loop @@rlp
  1815.        pop  ds
  1816.       ret
  1817. ; end fread
  1818. dos_shell endp
  1819.  
  1820.  
  1821. if HARD_DISC_TOO
  1822.  
  1823. create_harddisc proc
  1824.  
  1825.        call @@fopen
  1826.             jc short @@exit
  1827.  
  1828. ; we use secbuf as buffer, therefore it's contents must
  1829. ; be invalidated
  1830.        invalidate_rdbuf
  1831.  
  1832.  
  1833. ; fill a buffer of 1K with empty byte
  1834.        push es
  1835.        push ds
  1836.        pop es
  1837.        mov cx,1024/2
  1838.        mov ax,0e5e5h
  1839.        mov di,offset secbuf
  1840.        rep stosw
  1841.        pop es
  1842.  
  1843.        mov cx,(DRMH+1)*32/1024   ; size of directory in K
  1844.  
  1845. @@wrloop:
  1846.        push cx
  1847.        mov  cx,1024
  1848.        mov  dx,offset secbuf
  1849.        mov bx,handle
  1850.        DOS WRITE_TO_HANDLE
  1851.        CALLC disp_disk_err
  1852.        pop cx
  1853.        loop @@wrloop
  1854.  
  1855.        call @@fclose
  1856. @@exit:
  1857.        ret
  1858.  
  1859.  
  1860. @@fopen:
  1861.        mov cx,0
  1862.        mov dx,offset harddisc_fname
  1863.        DOS CREATE_FILE
  1864.        CALLC disp_disk_err
  1865.        mov handle,ax
  1866.        ret
  1867.  
  1868. @@fclose:
  1869.        mov bx,handle
  1870.        DOS CLOSE_FILE
  1871.        CALLC disp_disk_err
  1872.        ret
  1873. create_harddisc endp
  1874. endif
  1875.  
  1876.  
  1877. if HARD_DISC_TOO
  1878. init_harddisc proc
  1879.  
  1880.        PUSHR <ax,bx,cx,dx,si,di>
  1881.  
  1882.        cmp new_hdsk_flg,TRUE ; /C
  1883.        CALLZ create_harddisc
  1884.  
  1885.        mov al,2             ; read/write
  1886.        mov  dx,offset harddisc_fname
  1887.        DOS OPEN_FILE
  1888.        jc short @@exit       ; not found
  1889.  
  1890.        mov hd_handle,ax      ; also flag for hd present
  1891.  
  1892. @@exit:
  1893.        POPR <di,si,dx,cx,bx,ax>
  1894.        ret
  1895. init_harddisc endp
  1896. endif
  1897.  
  1898. init_ramdisc proc
  1899.        push es
  1900.        PUSHR <ax,cx>
  1901.        mov ax,ramdisklen          ; in paragraphen
  1902.        LOG2(64)                   ; nach cl (1024/16)
  1903.        shr ax,cl                  ; ax:=ramdisk len in KB
  1904.        and ax,0fff0h or 1100b     ; um Vielfache von 4K zu bekommen
  1905.        cmp ax,max_rd_size
  1906.        jna short @@rd_too_big
  1907.        mov ax,max_rd_size
  1908. @@rd_too_big:
  1909.        push ax
  1910.        LOG2(4)
  1911.        shr ax,cl                  ; ax/=4
  1912.        mov lasttrack_rd,al        ; Tracks zu 4 K
  1913.        pop ax
  1914.                                   ; dsm=ramdisklen in K/2 -1 , da bls=2k
  1915.        shr ax,1                   ; geht klar, da sowieso vielfaches von 4
  1916.        dec ax
  1917.        cmp ax,255
  1918.        jna short @@nobig
  1919.        mov ax,255                 ; mehr wie 510k geht im PC sowieso kaum
  1920.    @@nobig:
  1921.        mov dpb1.dsm,ax            ; blockzahl
  1922.        inc ax                     ; da KB=(dsm+1)*2
  1923.        shl ax,1
  1924.        mov ramdisklen,ax          ; KBzahl
  1925.        mov dpb1.bsh,4
  1926.        mov dpb1.blm,15
  1927.        mov dpb1.exm,1             ; blocksize=2048
  1928.        mov dpb1.drm,127           ; dir entries
  1929.        mov dpb1.al0,11000000b
  1930.  
  1931.                                   ; loesche ramdisc
  1932.        mov ax,rdseg_adr
  1933.        mov es,ax
  1934.        mov ax,ramdisklen
  1935. @@clrloop:
  1936.        cmp ax,64 ; k
  1937.        jb  short @@less64
  1938.        push ax
  1939.        mov cx,8000h               ; do 32k words
  1940.        mov di,0
  1941.        mov ax,0e5e5h
  1942.        rep stosw                  ; es:di := E5E5
  1943.        mov ax,es
  1944.        add ax,1000h
  1945.        mov es,ax
  1946.        pop ax
  1947.        sub ax,64
  1948.        jmp @@clrloop
  1949. @@less64:
  1950.        LOG2(512)
  1951.        shl ax,cl                  ; ax*=1024/2 (word)
  1952.        mov cx,ax
  1953.        mov di,0
  1954.        mov ax,0e5e5h
  1955.        rep stosw                  ; es:di := E5E5
  1956.        POPR <cx,ax>
  1957.        pop es
  1958.        call load_ramdisc
  1959.       ret
  1960. init_ramdisc endp
  1961.  
  1962. ; speichere Ramdisk auf Platte
  1963. ;
  1964. ; der LOCAL Befehl legt lokale Auto-Vars auf dem Stack an mit
  1965. ; Laenge AUTO_SIZE
  1966. ;
  1967. save_ramdisc proc
  1968. LOCAL  handle:WORD = AUTO_SIZE
  1969.  
  1970.        push bp
  1971.        mov  bp,sp
  1972.        sub  sp,AUTO_SIZE
  1973.        call @@fopen
  1974.             jc short @@exit
  1975.        call @@fwrite
  1976.        call @@fclose
  1977. @@exit:
  1978.        mov  sp,bp
  1979.        pop  bp
  1980.        ret
  1981.  
  1982.  
  1983. @@fopen:
  1984.        mov cx,0
  1985.        mov dx,offset ramdisc_fname
  1986.        DOS CREATE_FILE
  1987.        CALLC disp_disk_err
  1988.        mov handle,ax
  1989.        ret
  1990.  
  1991. @@fclose:
  1992.        mov bx,handle
  1993.        DOS CLOSE_FILE
  1994.        CALLC disp_disk_err
  1995.        ret
  1996.  
  1997. @@fwrite:
  1998.        ; erst mal Ramdiskgroesse schreiben, beim Laden muss sie stimmen
  1999.  
  2000.        mov bx,offset secbuf
  2001.        mov ax,ramdisklen
  2002.        mov [bx],ax
  2003.        mov dx,bx
  2004.        mov bx,handle
  2005.        mov cx,2
  2006.        DOS WRITE_TO_HANDLE
  2007.        CALLC disp_disk_err
  2008.  
  2009.        mov bx,rdseg_adr
  2010.        mov ax,ramdisklen
  2011. @@wrtloop:
  2012.        cmp  ax,0                  ; fertig ?
  2013.                                   ; 0 oder negativ = Abbruch
  2014.        jle short @@wrtexit
  2015.        push ax
  2016.        cmp ax,32                  ; kilobyte
  2017.        mov  cx,8000h ; 32k
  2018.        ja  short @@more32
  2019.        LOG2(1024)                 ; nach cl
  2020.        shl ax,cl                  ; ax*=1024
  2021.        mov cx,ax                  ; cx = Laenge in Byte
  2022. @@more32:
  2023.        push bx
  2024.          push ds
  2025.          push bx
  2026.          pop  ds
  2027.          mov  bx,handle           ; klappt, da ueber SS:BP
  2028.          mov  dx,0 ; offset
  2029.          DOS WRITE_TO_HANDLE
  2030.          CALLC disp_disk_err
  2031.          pop  ds
  2032.        pop bx
  2033.        pop ax
  2034.        add bx,800h                ; segment um 32k weitersetzen
  2035.        sub ax,32                  ; restlaenge -=32
  2036.       jmp @@wrtloop
  2037. @@wrtexit:
  2038.       ret
  2039. ; end fwrite
  2040. save_ramdisc endp
  2041.  
  2042.  
  2043. ; hole Ramdisk von Platte
  2044. ;
  2045. ; der LOCAL Befehl legt lokale Auto-Vars auf dem Stack an mit
  2046. ; Laenge AUTO_SIZE
  2047. ;
  2048. load_ramdisc proc
  2049. LOCAL  handle:WORD = AUTO_SIZE
  2050.  
  2051.        push bp
  2052.        mov  bp,sp
  2053.        sub  sp,AUTO_SIZE
  2054.        call @@fopen
  2055.        jc   short @@exit           ; nicht da
  2056.  
  2057.        call @@fread
  2058.        call @@fclose
  2059. @@exit:
  2060.        mov  sp,bp
  2061.        pop  bp
  2062.        ret
  2063.  
  2064.  
  2065. @@fopen:
  2066.        mov al,0
  2067.        mov dx,offset ramdisc_fname
  2068.        DOS OPEN_FILE
  2069.        mov handle,ax
  2070.        ret
  2071.  
  2072. @@fclose:
  2073.        mov bx,handle
  2074.        DOS CLOSE_FILE
  2075.        CALLC disp_disk_err
  2076.        ret
  2077.  
  2078. @@fread:
  2079.        mov dx,offset secbuf
  2080.        mov bx,handle
  2081.        mov cx,2
  2082.        DOS READ_FROM_HANDLE
  2083.        CALLC disp_disk_err
  2084.        mov bx,dx
  2085.        mov bx,[bx]
  2086.        cmp bx,ramdisklen
  2087.        ja  short @@rdexit         ; ueberhaupt zu gross
  2088.  
  2089.        mov ax,bx                  ; Laenge Ramdisk auf Platte
  2090.        mov bx,rdseg_adr
  2091. @@rdloop:
  2092.        cmp  ax,0                  ; fertig ?
  2093.        jle short @@rdexit
  2094.        push ax
  2095.        cmp ax,32
  2096.        mov  cx,8000h              ; 32k
  2097.        ja  short @@more32
  2098.        LOG2(1024)                 ; nach cl
  2099.        shl ax,cl                  ; ax*=1024
  2100.        mov cx,ax                  ; cx = Laenge in Byte
  2101. @@more32:
  2102.        push bx
  2103.          push ds
  2104.          push bx
  2105.          pop  ds
  2106.          mov  bx,handle           ; klappt, da ueber SS:BP
  2107.          mov  dx,0                ; offset
  2108.          DOS READ_FROM_HANDLE
  2109.          CALLC disp_disk_err
  2110.          pop  ds
  2111.        pop bx
  2112.        pop ax
  2113.        add bx,800h                ; segment um 32k weitersetzen
  2114.        sub ax,32                  ; restlaenge -=32
  2115.       jmp short @@rdloop
  2116. @@rdexit:
  2117.       ret
  2118. ; end fread
  2119. load_ramdisc endp
  2120.  
  2121. in_emu_flg db FALSE
  2122. count1 db 0
  2123. count2 db 0
  2124. bios88 proc
  2125. ;
  2126. ; bios88 ist handler fuer alle bios calls
  2127. ; In:  al=bios nummer (warm boot = 1)
  2128. ;      cx,bx,dx wie bei cp/m bios calls
  2129. ; Out: di,ah zerstoert
  2130. ;         si kann veraendert sein, falls bios change_si_flag
  2131. ;            hat nach wboot
  2132. ;
  2133. ; waehrend aller bios routinen zeigt ds auf emudata_seg
  2134. ;                                    es     z80cpu_seg
  2135.  
  2136.        mov cs:in_emu_flg,FALSE
  2137.        mov di,emudata_seg
  2138.        mov ds,di
  2139.  
  2140.        mov z80_pc,si
  2141.  
  2142.        cmp breakflag,TRUE
  2143.  
  2144.        CALLZ prg_exit
  2145.  
  2146.        PUSHR <bp,dx>
  2147. ; cx nicht pushen, da cl:=drive # bei wboot
  2148.  
  2149.        cmp al,30
  2150.        jna short @@goodfn
  2151.        mov al,1                   ; illegal function -> warmboot
  2152. @@goodfn:
  2153.        xor ah,ah                  ; bios # = index
  2154.        sal ax,1
  2155.        mov di,ax
  2156.  
  2157.          call cs:biostab[di]
  2158.        mov     si,z80_pc
  2159.  
  2160.        POPR  <dx,bp>
  2161.  
  2162.        cmp breakflag,TRUE
  2163.  
  2164.        CALLZ  prg_exit
  2165.  
  2166.        mov di,z80seg_adr
  2167.        mov ds,di
  2168.        mov es,di
  2169.        mov cs:in_emu_flg,TRUE
  2170.        jmp bios88ret
  2171.  
  2172. bios88 endp
  2173.  
  2174.  
  2175. biostab label word
  2176.         dw boot                   ; cold start
  2177.         dw wboot                  ; warm start
  2178.         dw constat                ; console status
  2179.         dw conin                  ; console character in
  2180.         dw conout                 ; console character out
  2181.         dw list                   ; list character out
  2182.         dw punch                  ; punch character out
  2183.         dw reader                 ; reader character out
  2184.         dw home                   ; move head to home position
  2185.         dw seldsk                 ; select disk
  2186.         dw settrk                 ; set track number
  2187.         dw setsec                 ; set sector number
  2188.         dw setdma                 ; set dma address
  2189.         dw read                   ; read disk
  2190.         dw write                  ; write disk
  2191.         dw listst                 ; return list status
  2192.         dw sectran                ; sector translate
  2193.         rept 25-16-1
  2194.           dw wboot                ; not used
  2195.         endm
  2196.         dw cpm3_move              ; move
  2197.         dw cpm_get_time           ; time
  2198.         rept 30-26-1
  2199.           dw wboot                ; not used
  2200.         endm
  2201.         dw userfn                 ; here: used for data transfer dos/cpm
  2202. ;
  2203. ;
  2204. ;  individuelle UPs um jede Funktion auszufuehren
  2205. ;
  2206. boot proc
  2207.  
  2208. ;simplest case is to just perform parameter initialization
  2209.        mov in_boot_flag,TRUE
  2210.        mov bx,offset on_sign_string
  2211.        call puts
  2212.  
  2213.        call instzbios
  2214.  
  2215.        cmp  fmt_file_flg,TRUE
  2216.        CALLZ load_disk_pars
  2217.  
  2218.  
  2219.        call read_sys  ; lade bdos aus file CPMSYS.CPM
  2220.        jnc  short @@goodload ; laden aus File klappte
  2221.        call get_sys   ; BDOS mit BIOS fkt von Diskette laden
  2222. @@goodload:
  2223.  
  2224. ; Copyright von dr ausgeben
  2225.  
  2226.        mov cl,27
  2227.        call crtout
  2228.        mov cl,'k'                 ; pop cursor pos
  2229.        call crtout
  2230.        mov cl,27
  2231.        call crtout
  2232.        mov cl,'J'                 ; Rest vom Fenster loeschen
  2233.        call crtout
  2234.  
  2235.        mov bx,offset cpm_bdos_buf+18h
  2236.        call puts
  2237.  
  2238.        mov bx,offset cr_lf_txt
  2239.        call puts
  2240. ;
  2241. ; berechne adresse von ccp,bdos und bios
  2242. ; dabei wird die JMP CCPENTRY Anweisung bei CCP+0 benutzt
  2243. ;
  2244.        mov di,offset cpm_bdos_buf+807h
  2245.        mov al,[di]
  2246.        cmp al,11h
  2247.        jnz short @@no_standard
  2248.        mov di,offset cpm_bdos_buf+1
  2249.        mov ax,[di]
  2250.        sub ax,35ch                ; ax:=start ccp
  2251. ; CP/M CCP? dann al jetzt 0
  2252.        or al,al
  2253.        jz short @@is_standard
  2254. ; sonst defaultmaessig e400 annehmen
  2255. @@no_standard:
  2256.        mov ax,0e400h
  2257. @@is_standard:
  2258.        mov ccp_adr,ax
  2259.        add  ax,806h
  2260.        mov bdos_adr,ax
  2261.        add  ax,(BDOSLEN-806h)
  2262.        mov bios_adr,ax
  2263.  
  2264.        call reset_crt
  2265.  
  2266.        call init_iobyte
  2267.  
  2268.        mov di,CDISK
  2269.        mov byte ptr es:[di],0     ; select disk zero
  2270.        call reset_punch_buf
  2271.        call reset_reader_buf
  2272.        mov in_boot_flag,FALSE
  2273.        jmp  wboot
  2274. boot endp
  2275.  
  2276. init_iobyte proc
  2277.        mov di,IOBYTE
  2278.        mov byte ptr es:[di],DEFAULT_IOBYTE   
  2279.      ret
  2280. init_iobyte endp
  2281. ;
  2282. ; setze Punch buffer auf leer
  2283. ;
  2284.  
  2285. reset_punch_buf proc
  2286.        mov punch_buf_entries,0
  2287.        mov punch_buf_ptr,offset punch_buf
  2288.        ret
  2289. reset_punch_buf endp
  2290.  
  2291.  
  2292. ;
  2293. ; setze Reader buffer auf nicht belegt
  2294. ;
  2295.  
  2296. reset_reader_buf proc
  2297.        mov reader_empty_flag,FALSE     ; noch nicht lesen versucht
  2298.        mov reader_buf_entries,0
  2299.        mov reader_buf_ptr,offset reader_buf
  2300.        mov reader_file_pointer,0
  2301.        mov reader_file_pointer+2,0
  2302.        ret
  2303. reset_reader_buf endp
  2304.  
  2305. ;
  2306. ; Stringausgabe
  2307. ; In: ds:bx zeigt auf String, Stringende = \0
  2308. ;
  2309. puts proc
  2310. @@loop:
  2311.        mov cl,[bx]
  2312.        or  cl,cl
  2313.        jz  short @@exit
  2314.        inc bx
  2315.        push bx
  2316.        call crtout
  2317.        pop  bx
  2318.        jmp short @@loop
  2319. @@exit:ret
  2320. puts endp
  2321.  
  2322. ;
  2323. ; In: ds:si = source, es:di = target
  2324. ; copy string-zero
  2325. ;
  2326. strcpy proc
  2327.         push ax
  2328. @@loop:
  2329.         lodsb
  2330.         stosb
  2331.         or al,al
  2332.         jnz short @@loop
  2333.         pop ax
  2334.         ret
  2335. strcpy endp
  2336.  
  2337. instzbios proc
  2338. ;
  2339. ; installiere z80 bios
  2340. ; und discparameter
  2341. ;
  2342.  
  2343.        PUSHR <si,di,cx>
  2344.  
  2345.          mov  si,offset zbiosbeg
  2346.          mov  di,ZBIOS
  2347.          mov  cx,zbiosend-zbiosbeg
  2348.          cld
  2349.          rep movsb                ; es:di := ds:si
  2350.  
  2351.        POPR <cx,di,si>
  2352.        ret
  2353. instzbios endp
  2354.  
  2355.  
  2356. instjp proc
  2357. ;
  2358. ; installiere z80 bios Sprungleiste bei bios_adr
  2359. ;
  2360. ; register o.k.
  2361. ;
  2362. ; darf nicht aufgerufen werden, bevor bios_adr
  2363. ; von boot aufgesetzt wurde
  2364. ;
  2365.  
  2366.        PUSHR <si,di,cx>
  2367.  
  2368.          mov  si,offset wboote-3
  2369.          mov  di,bios_adr
  2370.          mov  cx,zvecend-wboote+3
  2371.          cld
  2372.          rep movsb                ; es:di := ds:si
  2373.  
  2374.        POPR <cx,di,si>
  2375.  
  2376.        ret
  2377. instjp endp
  2378.  
  2379.  
  2380. read_sys  proc
  2381. ;
  2382. ; lade cp/m bdos aus file CPMSYS.CPM in buffer
  2383. ; um es durch warm boot zu benutzen
  2384. ;
  2385. ; das File entspricht dem durch MOVCPM erzeugten Speicherauszug
  2386. ; dabei beginnt das eingentlich System erst ab Offset 880h
  2387.  
  2388. MOVCPM_OFFS = 880H
  2389.  
  2390.      PUSHR <ax,bx,cx,dx,si>
  2391.        mov al,0
  2392.        mov dx,offset cpmsys_fileName
  2393.        DOS OPEN_FILE
  2394.        jc  short @@exit
  2395.        mov si,ax
  2396.        ; setze Filepointer auf CCP Anfang im File
  2397.        mov cx,0                   ; cx:dx: offset
  2398.        mov dx,MOVCPM_OFFS
  2399.        mov al,0                   ; offset from start
  2400.        mov bx,si
  2401.        DOS MOVE_FILE_POINTER
  2402. ;
  2403. ; emudata_seg:buffer := CPMSYS.CPM
  2404. ;
  2405.        mov cx,BDOSLEN             ; Laenge
  2406.        mov bx,si                  ; handle
  2407.        mov dx,offset cpm_bdos_buf
  2408.        DOS READ_FROM_HANDLE
  2409.        jc  short @@exit
  2410.        mov bx,si
  2411.        DOS CLOSE_FILE
  2412.        CALLC disp_disk_err
  2413. @@exit:
  2414.        POPR <si,dx,cx,bx,ax>
  2415.        ret
  2416. read_sys  endp
  2417.  
  2418.  
  2419. ; System von SystemSpuren laden
  2420.  
  2421. ; while sector in systemsectoren do
  2422. ;    lies sector
  2423. ;    if an Adresse     String COPYRIGHT 1979 ..
  2424. ;       sys=naechste SYS_SECS sektoren
  2425. ;       lies sys
  2426. ;       exit
  2427. ;       mache Checksumme ueber sys
  2428. ;       if falsch
  2429. ;          "no sys"
  2430. ;       endif
  2431. ;    endif
  2432. ; endwhile
  2433. ; "no sys"
  2434.  
  2435. get_sys proc
  2436. LOCAL  sys_recs,last_sys_rec:WORD = AUTO_SIZE
  2437.  
  2438.        push bp
  2439.        mov  bp,sp
  2440.        sub  sp,AUTO_SIZE
  2441. @@get_sys_loop:
  2442.        call login_disc
  2443.        call home                  ; else dir track will not be read
  2444.        mov  ah,0                  ; take drive A: = floppy disc
  2445.        mov  al,dpb0.off-dpb0.spt  ; off
  2446.        call get_dpb_entrie        ; nach bx
  2447.        push bx
  2448.        mov  ah,0                  ; A:
  2449.        mov  al,dpb0.spt-dpb0.spt  ; spt
  2450.        call get_dpb_entrie        ; nach bx
  2451.        pop  ax
  2452.        mul  bx                    ; ax:=system records
  2453.        mov  sys_recs,ax
  2454.        mov  cx,0
  2455. ; im Systembereich nach String "COPYRIGHT (C) 1979 " suchen
  2456. @@srch_loop:
  2457.        cmp  cx,sys_recs
  2458.        jnc  short @@read_err      ; schon ausserhalb sys
  2459.        push cx  ; sector
  2460.        push cx
  2461.        mov  cx,DEFAULT_DMA
  2462.        call setdma
  2463.        pop  cx
  2464.        mov  ah,0                  ; A:
  2465.        call set_abs_sect
  2466.        call read
  2467.        pop  cx
  2468.        cmp  al,1
  2469.        jz   short @@read_err
  2470.        call @@compare
  2471.        jz   short @@found
  2472.        inc  cx
  2473.        jnz  @@srch_loop
  2474. @@found:
  2475.        mov  bx,DEFAULT_DMA
  2476.        push cx
  2477.        add  cx,SYS_SECS
  2478.        mov  last_sys_rec,cx
  2479.        pop  cx
  2480. @@loop:
  2481.        push cx  ; sector
  2482.        push bx  ; dma
  2483.        push cx
  2484.        mov  cx,bx
  2485.        call setdma
  2486.        pop  cx
  2487.        mov  ah,0                  ; take drive A: = floppy disc
  2488.        call set_abs_sect
  2489.        call read
  2490.        pop  bx
  2491.        pop  cx
  2492.        cmp  al,1
  2493.        jz   short @@read_err
  2494.        add  bx,RECORD_LEN
  2495.        inc  cx
  2496.        cmp  cx,last_sys_rec
  2497.        jnz  @@loop
  2498.  
  2499.        jmp  short @@good_load
  2500.  
  2501. @@read_err:
  2502.        mov  bx,offset no_sys
  2503.        call puts
  2504.        call crtin
  2505.        jmp  @@get_sys_loop
  2506.  
  2507. @@good_load:
  2508.  
  2509. ; System aus CP/M Segment nach Datensegment uebertragen
  2510.  
  2511.        PUSHR <si,di,bx,cx,ax>
  2512.        push ds
  2513.        push es
  2514.          mov di,offset cpm_bdos_buf
  2515.          mov si,DEFAULT_DMA
  2516.          mov ax,z80seg_adr
  2517.          mov ds,ax
  2518.          mov ax,emudata_seg
  2519.          mov es,ax
  2520.          mov cx,BDOSLEN/2
  2521.          cld
  2522.          rep movsw                ; es:di := ds:si
  2523.        pop es
  2524.        pop ds
  2525.        POPR <ax,cx,bx,di,si>
  2526.        mov  sp,bp
  2527.        pop  bp
  2528.        ret
  2529. @@compare:
  2530.        PUSHR <si,di,cx,ax>
  2531.        mov  si,offset bdos_str
  2532.        mov  di,DEFAULT_DMA+10H
  2533.        mov  cx,bdos_str_end-bdos_str
  2534. @@cp_loop:
  2535.        mov al,[es:di]
  2536.        mov ah,[si]
  2537.        inc si
  2538.        inc di
  2539.        cmp al,ah
  2540.        jnz  short @@cp_exit
  2541.        loop @@cp_loop
  2542. @@cp_exit:
  2543.        POPR <ax,cx,di,si>
  2544.        ret
  2545.  
  2546. get_sys endp
  2547. ;
  2548.  
  2549. set_abs_sect proc    ; absoluten Sektor in cx, drive ah setzen
  2550.        push cx
  2551.        mov  al,0                  ; spt
  2552.        call get_dpb_entrie        ; nach bx
  2553.        pop  ax
  2554.        mov  dx,0
  2555.        div  bx
  2556.        push dx
  2557.        mov  cx,ax
  2558.        call settrk
  2559.        pop  cx
  2560.        call setsec
  2561.        ret
  2562. set_abs_sect endp
  2563.  
  2564.  
  2565. wboot proc
  2566.  
  2567.      push   di
  2568.        call   copy_bdos
  2569.        call   instjp              ; bios Sprungleiste installieren
  2570. ;
  2571. ; 0000h := JP WBOOT
  2572. ; 0005h := JP BDOS
  2573. ;
  2574.        mov     di,0               ; start cp/m memory
  2575.        mov     byte ptr es:[di+0],0c3h
  2576.        mov     bx,bios_adr
  2577.        add     bx,3               ; bx:=warmboot
  2578.        mov     es:[di+1],bx       ; set address field for jmp at 0
  2579. ;
  2580.        mov     byte ptr es:[di+5],0c3h
  2581.        mov     bx,bdos_adr        ; bdos entry point
  2582.        mov     es:[di+6],bx       ; address field of jump at 5 to bdos 
  2583. ;
  2584.        mov     cx,DEFAULT_DMA     ; default dma address is 80h
  2585.        call   setdma
  2586.  
  2587.        call login_disc ; physikalisches Login
  2588. ;
  2589.        mov     ax,ccp_adr
  2590.        mov     z80_pc,ax          ; jp ccp
  2591.  
  2592.        mov     di,CDISK
  2593.        mov     cl,es:[di]         ; get current disk number & send to ccp 
  2594.      pop di
  2595.      ret                          ;go to cp/m for further processing
  2596.  
  2597. copy_bdos:
  2598.        PUSHR <si,di,cx>
  2599.  
  2600.          mov di,ccp_adr
  2601.          mov si,offset cpm_bdos_buf
  2602.          mov cx,BDOSLEN/2
  2603.          rep movsw                ; es:di := ds:si
  2604.  
  2605.        POPR <cx,di,si>
  2606.        ret
  2607.  
  2608. wboot  endp
  2609. ;
  2610.  
  2611. ;
  2612. ;
  2613. constat proc
  2614. ;
  2615. ; console status, return 0ffh if character ready, 00h,Z_flag if not
  2616. ;
  2617. ; Out: al=status
  2618. ;
  2619.         mov bx,IOBYTE
  2620.         mov bl,es:[bx]
  2621.         and bx,11b
  2622.         add bx,bx
  2623.         jmp cs:consttab[bx]
  2624.  
  2625. consttab label word
  2626.        dw offset crtinstat
  2627.        dw offset crtinstat
  2628.        dw offset readstat
  2629.        dw offset crtinstat
  2630.  
  2631. constat endp
  2632.  
  2633. ;
  2634. ;
  2635. conin proc   ; CON:
  2636. ;
  2637. ; Out: al=char
  2638. ;
  2639.         mov bx,IOBYTE
  2640.         mov bl,es:[bx]
  2641.         and bx,11b
  2642.         add bx,bx
  2643.         jmp cs:conintab[bx]
  2644. conintab label word
  2645. ; -> consttab
  2646.        dw offset crtin      ;  TTY:
  2647.        dw offset crtin      ;  CRT:
  2648.        dw offset reader     ;  BAT:
  2649.        dw offset crtin      ;  UC1:
  2650. conin endp
  2651.  
  2652. conout proc  ; CON:
  2653. ;
  2654. ; In: c=char
  2655. ;
  2656.         mov bx,IOBYTE
  2657.         mov bl,es:[bx]
  2658.         and bx,11b
  2659.         add bx,bx
  2660.         mov al,1
  2661.         jmp cs:conouttab[bx]
  2662. conouttab label word
  2663.        dw offset crtout    ;  TTY:
  2664.        dw offset crtout    ;  CRT:
  2665.        dw offset punch     ;  BAT:
  2666.        dw offset crtout    ;  UC1:
  2667. conout endp
  2668.  
  2669.  
  2670. ;
  2671. ; test auf ^C, wenn ja, warm boot
  2672. ;
  2673. tst_ctrl_c proc
  2674.        push ax
  2675.        call constat
  2676.        jz   short @@exit
  2677.        call crtin
  2678.        cmp  al,3                  ; ^C
  2679.        clc                        ; cy = no error
  2680.        jnz  short @@exit
  2681.        mov  bx,offset control_c_txt
  2682.        call puts
  2683.        stc
  2684. @@exit:
  2685.        pop ax
  2686.        ret
  2687. tst_ctrl_c endp
  2688.  
  2689. list proc  ; LST:
  2690.     mov bx,IOBYTE
  2691.     mov bl,es:[bx]
  2692.     and bx,11000000b
  2693.     shr bx,6-1
  2694.     jmp cs:lsttab[bx]
  2695. lsttab label word
  2696.        dw offset crtout      ; TTY:
  2697.        dw offset crtout      ; CRT:
  2698.        dw offset lpt0list    ; LPT:
  2699.        dw offset lpt1list    ; UL1:
  2700. list endp
  2701.  
  2702. lpt0list proc
  2703.         xor dx,dx
  2704.         jmp short lptlist
  2705. lpt0list endp
  2706.  
  2707. lpt1list proc
  2708.         mov dx,1
  2709.         jmp short lptlist
  2710. lpt1list endp
  2711.  
  2712. ;
  2713. ; list character in register c auf Drucker
  2714. ;
  2715. lptlist proc
  2716.        call listst
  2717.        jnz  short @@ok
  2718.        call tst_ctrl_c
  2719.        jnc  short lptlist
  2720.        mov  z80_pc,0              ; Z80 macht ab Adresse 0 weiter
  2721.        ret
  2722. @@ok:
  2723.        mov al,cl                  ; char nach register a
  2724.        xor ah,ah                  ; list character
  2725.        push bp
  2726.        int 17h
  2727.        pop bp
  2728.        cmp ah,10h                 ; ok
  2729.        jnz short lptlist
  2730.        ret
  2731. lptlist endp
  2732. ;
  2733. ; return list status (0,Z_flag if not ready, 1 if ready)
  2734. ;
  2735. listst proc
  2736.        push dx
  2737.        mov ah,2                   ; test printer
  2738.        int 17h
  2739.        mov al,1
  2740.        cmp ah,90h                 ; on line und not busy
  2741.        jz short @@lret
  2742.        dec al
  2743. @@lret:
  2744.        or  al,al
  2745.        pop dx
  2746.        ret
  2747. listst endp
  2748.  
  2749.  
  2750. com0list proc
  2751.         xor dx,dx
  2752.         jmp short comlist
  2753. com0list endp
  2754.  
  2755. com1list proc
  2756.         mov dx,1
  2757.         jmp short comlist
  2758. com1list endp
  2759.  
  2760. comlist proc
  2761.         mov ah,1
  2762.         mov al,cl
  2763.         int 14h
  2764.         ret
  2765. comlist endp
  2766.  
  2767. com0read proc
  2768.         xor dx,dx
  2769.         jmp short comread
  2770. com0read endp
  2771.  
  2772. com1read proc
  2773.         mov dx,1
  2774.         jmp short comread
  2775. com1read endp
  2776.  
  2777. comread proc
  2778.         mov ah,2
  2779.         mov al,cl
  2780.         int 14h
  2781.         ret
  2782. comread endp
  2783.  
  2784. date_dos_2_cpm proc  ; out: AX=tage seit 1.Jan. 1978
  2785.     push bx
  2786.     push cx
  2787.     push dx
  2788.     DOS GET_DATE
  2789.     push dx
  2790.     mov bx,1978
  2791.     inc cx      ; ein Jahr zuviel, für Test ob akt. Schaltjahr
  2792.     MOV AX,0
  2793. @@add_loop:
  2794.     cmp  bx,cx  ; aktuelles Jahr erreicht ?
  2795.     jz short @@years_done
  2796.  
  2797.     mov  dx,bx
  2798.     and  dx,11b ; 0 => durch 4 teilbar
  2799.     sub  dx,1   ; 0 => cy
  2800.     mov  dx,365
  2801.     adc  dx,0   ; wird unten zum abziehen gebraucht
  2802.     add  ax,dx  ; 0 => 366
  2803.  
  2804.     inc  bx
  2805.     jmp  @@add_loop
  2806. @@years_done:
  2807.     sub ax,dx  ; da ein Jahr oben zuviel, 365 oder 366 wieder weg
  2808.     pop dx   ; mon/tag
  2809.     mov ch,0
  2810.     mov cl,dl
  2811.     add ax,cx ; tag
  2812.     mov cl,dh ; monat
  2813.     dec cl    ; da aktueller Monat schon dran
  2814.     jz  short @@is_jan
  2815.     mov bx,offset month_tab
  2816. @@add_months:
  2817.     mov dl,[bx]    ; verschieden lange monate
  2818.     inc bx
  2819.     mov dh,0
  2820.     add ax,dx
  2821.     loop @@add_months
  2822. @@is_jan:
  2823.     pop dx
  2824.     pop cx
  2825.     pop bx
  2826.     ret
  2827. date_dos_2_cpm endp
  2828.  
  2829. cpm3_move proc   ; move wie bei cpm plus bios
  2830.     push ds
  2831.     push es
  2832.     pop  ds
  2833.     mov  si,bx
  2834.     mov  di,dx
  2835.     add  bx,cx      ; hl=blockende
  2836.     cmp  bx,dx      ; größer Ziel ?
  2837.     jnb   short @@topdown
  2838.     cld
  2839.     rep movsb
  2840.     jmp short @@exit
  2841. @@topdown:
  2842.     add si,cx
  2843.     add di,cx
  2844.     mov bx,si
  2845.     mov dx,di
  2846.     dec si
  2847.     dec di
  2848.     std
  2849.     rep movsb
  2850.     pop ds
  2851.     ret
  2852. @@exit:
  2853.     mov bx,si
  2854.     mov dx,di
  2855.     pop ds
  2856.    ret
  2857. cpm3_move endp
  2858.  
  2859.  
  2860. cpm_get_time proc   ; dos zeit nach cpm plus zeit
  2861.     PUSHR <AX,CX,DX>
  2862.     cmp cl,0
  2863.     jnz short @@exit ; set time ignorieren
  2864.     call date_dos_2_cpm
  2865.     push ds
  2866.     push es
  2867.     pop  ds
  2868.     mov @date+ZBIOSDISPL,ax
  2869.     DOS GET_TIME
  2870.     mov dl,10
  2871.     mov al,cl
  2872.     mov ah,0         ; sonst divide overflow
  2873.     div dl
  2874.     mov cl,4
  2875.     shl al,cl
  2876.     or  al,ah
  2877.     mov @min+ZBIOSDISPL,al
  2878.     mov al,ch
  2879.     mov ah,0
  2880.     div dl
  2881.     shl al,cl
  2882.     or  al,ah
  2883.     mov @hour+ZBIOSDISPL,al
  2884.     mov al,dh
  2885.     mov ah,0
  2886.     div dl
  2887.     shl al,cl
  2888.     or  al,ah
  2889.     mov @sec+ZBIOSDISPL,al
  2890.     pop ds
  2891.     mov bx,(offset @date)+ZBIOSDISPL
  2892. @@exit:
  2893.     POPR <DX,CX,AX>
  2894.     ret
  2895. cpm_get_time endp
  2896.         
  2897. del_punch_file proc
  2898.        mov dx,offset punch_fileName
  2899.        DOS DELETE_FILE
  2900.        ret
  2901. del_punch_file endp
  2902.  
  2903. ; on entry to all userfunctions:
  2904. ;  c = proc number
  2905. ; de = entry data
  2906. ; hl = pointer to variable, where to store return value
  2907. userfn proc
  2908.         cmp cl,10
  2909.         ja wboot             ; illegal function
  2910.         mov ch,0
  2911.         mov si,cx
  2912.         add si,si
  2913.         push bx              ; hl
  2914.         call cs:userfntab[si]
  2915.         pop  di
  2916.         xchg ax,bx
  2917.         stosw                ; es:di:=ax
  2918.         mov  ax,bx
  2919.         ret
  2920.  
  2921. userfntab label word
  2922.         dw versionfn         ; return version NR
  2923.         dw openout           ; open out to dos
  2924.         dw closeout          ; close out to dos
  2925.         dw doswrite          ; write record to dos
  2926.         dw dosexec           ; execute dos command
  2927.         dw setfname          ; set filename for getnextname ("*.c")
  2928.         dw getnextname       ; return next suitable name
  2929.         dw openin            ; open in dosfile
  2930.         dw dosread           ; read next record from dos
  2931.         dw closein           ; abandon dos file
  2932.         dw get_phys_drv      ; return physical drive number
  2933. ; don't forget to adapt test at start of userfn
  2934.  
  2935. userfn endp
  2936.  
  2937. ; return physical drive number
  2938. ; out: al = physical drive number
  2939. get_phys_drv proc
  2940.         mov al,cpm_drive
  2941.         mov ah,0
  2942.         ret
  2943. get_phys_drv endp
  2944.  
  2945. ; execute dos command
  2946. ; in: DE-> zero terminated command line
  2947. ; out: -
  2948. dosexec proc
  2949.         mov si,dx
  2950.         mov di,offset usr_lne
  2951.         mov cx,80            ; in order not to copy too much
  2952. @@loop:
  2953.         mov al,es:[si]
  2954.         cmp al,0
  2955.         jz  short @@copied
  2956.         mov ds:[di],al
  2957.         inc si
  2958.         inc di
  2959.         loop @@loop
  2960. @@copied:
  2961.         mov byte ptr ds:[di],13
  2962.         mov al,83
  2963.         sub al,cl
  2964.         mov byte ptr exec_usr_lne,al
  2965.         mov exec_usr_flg,TRUE
  2966.         mov [exec_par_block+2],offset exec_usr_lne
  2967. mov di,offset exec_par_block
  2968.         call dos_shell
  2969.         mov [exec_par_block+2],offset exec_cmd_line
  2970.         mov exec_usr_flg,FALSE
  2971.         mov al,0
  2972.        ret
  2973. dosexec endp
  2974.  
  2975. ; return version NR
  2976. versionfn proc
  2977.         mov ax,41751         ; identification of ZSIM
  2978.         mov bx,CVERSNR
  2979.         ret
  2980. versionfn endp
  2981.  
  2982. ; open out file to dos
  2983. ; in: DE-> zero terminated filename
  2984. ; out: if error A=1 else 0
  2985. ; first try to close an old file
  2986. openout proc
  2987.            push dx
  2988.            call closeout
  2989.            pop  dx
  2990.            push ds
  2991.            mov ax,es
  2992.            mov ds,ax         ; ds-> z80cpu seg
  2993.            mov cl,0 ; write only
  2994.            DOS CREATE_FILE
  2995.            CALLC disp_disk_err
  2996.            pop ds
  2997.            mov openout_handle,ax
  2998.            mov al,0
  2999.            adc al,0         ; error -> 1 else 0
  3000.           ret
  3001. openout endp
  3002.  
  3003. ; close outfile
  3004. ; in: -
  3005. ; out: if error A=1 else 0
  3006. closeout proc
  3007.         mov bx,openout_handle
  3008.         mov openout_handle,0
  3009.         cmp bx,0
  3010.         stc
  3011.         jz  short @@exit
  3012.         DOS CLOSE_FILE
  3013.         CALLC disp_disk_err
  3014. @@exit:
  3015.         mov al,0
  3016.         adc al,0
  3017.        ret
  3018. closeout endp
  3019.  
  3020. ; write 128 bytes to dos
  3021. ; in: DE -> data
  3022. ; out: if error A=1 else 0
  3023. doswrite proc
  3024.         push ds
  3025.         mov bx,openout_handle
  3026.         mov ax,es
  3027.         mov ds,ax         ; ds-> z80cpu seg
  3028.         mov cx,128
  3029.         DOS WRITE_TO_HANDLE
  3030.         CALLC disp_disk_err
  3031.         pop ds
  3032.         mov al,0
  3033.         adc al,0
  3034.        ret
  3035. doswrite endp
  3036.  
  3037. ; set filename for getnextname ("*.c\0")
  3038. ; in: DE -> fname
  3039. ; out: if error A=1 else 0
  3040. setfname proc
  3041.         mov cx,80
  3042.         mov di,offset dosfilespec
  3043.         mov si,dx
  3044. @@loop:
  3045.         mov al,es:[si]
  3046.         mov ds:[di],al
  3047.         or al,al
  3048.         jz short @@done
  3049.       
  3050.         inc si
  3051.         inc di
  3052.         loop @@loop
  3053.         mov al,1             ; Name is too long
  3054. @@done:                      ; A is 0
  3055.         mov new_dosfilespecflg,TRUE
  3056.         ret
  3057. setfname endp
  3058.  
  3059. ; return next suitable name
  3060. ; in: DE -> buffer to store filename
  3061. ; out: if error A=1 else 0
  3062. ; if found copy filename to buffer
  3063. getnextname proc
  3064.         push dx
  3065.  
  3066.         push ds
  3067.         lds dx,default_dta
  3068.         DOS SET_DTA
  3069.         pop ds
  3070.  
  3071.         TSTNCLR new_dosfilespecflg
  3072.         mov cx,0
  3073.         mov dx,offset dosfilespec
  3074.         jz short @@open_next
  3075.           DOS FIND_FIRST
  3076.           jmp short @@cont
  3077. @@open_next:
  3078.         DOS FIND_NEXT
  3079. @@cont:
  3080.         pop di
  3081.         mov al,1
  3082.         jc short @@exit
  3083.  
  3084.         push ds
  3085.         lds si,default_dta
  3086.         add si,1eh           ; si-> file name in dta returned
  3087. @@loop:
  3088.         lodsb                ; copy filename
  3089.         stosb
  3090.         or al,al             ; \0 ?
  3091.         jnz @@loop
  3092.         pop ds
  3093. @@exit:
  3094.         ret
  3095. getnextname endp
  3096.  
  3097. ; open in dosfile
  3098. ; in: DE -> filename\0
  3099. ; out: if error A=1 else 0
  3100. ; first try to close an old file
  3101. openin proc
  3102.         push dx
  3103.         call closein
  3104.         pop  dx
  3105.         push ds
  3106.         mov ax,es
  3107.         mov ds,ax
  3108.         mov al,0                                               
  3109.         DOS OPEN_FILE
  3110.         pop ds
  3111.         mov openin_handle,ax
  3112.         mov al,0
  3113.         adc al,0
  3114.         ret
  3115. openin endp
  3116.  
  3117. ; read next record from dos
  3118. ; in: DE -> buffer
  3119. ; out: if error A=1 else 0;HL=length (1..128)
  3120. dosread proc
  3121.         mov bx,openin_handle
  3122.         mov cx,128
  3123.         push ds
  3124.         mov ax,es
  3125.         mov ds,ax
  3126.         DOS READ_FROM_HANDLE
  3127.         pop ds
  3128.         mov bx,ax            ; length actually read
  3129.         mov al,0
  3130.         adc al,0
  3131.        ret
  3132. dosread endp
  3133.  
  3134. ; abandon dos file
  3135. ; in: -
  3136. ; out: if error A=1 else 0
  3137. ; is called before every openin
  3138. closein proc
  3139.         mov bx,openin_handle
  3140.         mov openin_handle,0
  3141.         cmp bx,0
  3142.         stc
  3143.         jz  short @@exit
  3144.         DOS CLOSE_FILE
  3145. @@exit:
  3146.         mov al,0
  3147.         adc al,0
  3148.        ret
  3149. closein endp
  3150.  
  3151. ;
  3152. ; punch character in register c
  3153. ; wird durch Output in File auf MsDos Disk ersetzt
  3154. ; Buffer wird auf File geschrieben, falls er voll ist
  3155. ; und  auch am Ende des Emulator-
  3156. ; laufs
  3157. ;
  3158. punch proc   ; PUN:
  3159.     mov bx,IOBYTE
  3160.     mov bl,es:[bx]
  3161.     and bx,110000b
  3162.     shr bx,4-1
  3163.     jmp cs:puntab[bx]
  3164. puntab label word
  3165.        dw offset filepunch   ; TTY:
  3166.        dw offset filepunch   ; PTP:
  3167.        dw offset com0list    ; UP1:
  3168.        dw offset com1list    ; UP2:
  3169. punch endp
  3170.  
  3171. filepunch proc
  3172. ;
  3173. ; fill buffer until full or eof
  3174. ; open file
  3175. ; if not exist file
  3176. ;    create file
  3177. ; endif
  3178. ; go to end of file
  3179. ; append character
  3180. ; close file
  3181. ; empty buffer
  3182. ;
  3183. ; falls punch von bios88 aufgerufen wurde, ist al<>0
  3184. ; nach Aufruf von wrt_out_punch aber al=0
  3185.  
  3186.      PUSHR <ax,bx,cx,dx,si>
  3187.        cmp al,0
  3188.        jz  short @@write_out
  3189.        mov bx,punch_buf_ptr
  3190.        mov [bx],cl                ; buf:=character
  3191.        inc bx
  3192.        mov punch_buf_ptr,bx
  3193.        inc punch_buf_entries
  3194.        cmp punch_buf_entries,PUNCH_BUF_SIZE
  3195.        jnz short @@exit
  3196. @@write_out:
  3197.        mov al,1
  3198.        mov dx,offset punch_fileName
  3199.        DOS OPEN_FILE
  3200.        jnc short @@file_found
  3201.            mov cl,0 ; write only
  3202.            DOS CREATE_FILE
  3203.            CALLC disp_disk_err
  3204. @@file_found:
  3205.  
  3206.        mov bx,ax                  ; handle
  3207.        mov cx,0
  3208.        mov dx,0
  3209.        mov al,2                   ; offset from end
  3210.        DOS MOVE_FILE_POINTER
  3211.  
  3212.        mov cx,punch_buf_entries
  3213.        mov dx,offset punch_buf
  3214.        DOS WRITE_TO_HANDLE
  3215.        CALLC disp_disk_err
  3216.  
  3217.        DOS CLOSE_FILE
  3218.  
  3219.        call reset_punch_buf
  3220. @@exit:
  3221.        POPR <si,dx,cx,bx,ax>
  3222.        ret
  3223. filepunch endp
  3224.  
  3225. wrt_out_punch proc
  3226.        cmp punch_buf_entries,0
  3227.        jz  short @@exit
  3228.        xor  al,al
  3229.        call punch
  3230. @@exit:
  3231.        ret
  3232. wrt_out_punch endp
  3233. ;
  3234. ; RDR:
  3235. reader proc       ;read character into register a from reader device
  3236.         mov bx,IOBYTE
  3237.         mov bl,es:[bx]
  3238.         and bx,1100b
  3239.         shr bx,2-1
  3240.         jmp cs:rdrtab[bx]
  3241. rdrtab label word
  3242.        dw offset filereader  ; TTY:
  3243.        dw offset filereader  ; PTR:
  3244.        dw offset com0read    ; UR1:
  3245.        dw offset com1read    ; UR2:
  3246. reader endp
  3247.  
  3248. filereader proc
  3249. ; if buffer empty
  3250. ;    open file
  3251. ;    if file not present
  3252. ;       exit
  3253. ;    else
  3254. ;       fill buffer
  3255. ;    endif
  3256. ; endif
  3257. ; read char
  3258.  
  3259.        cmp reader_empty_flag,TRUE
  3260.        jz  short @@empty
  3261.        cmp reader_buf_entries,0
  3262.        jnz short @@do_read
  3263.  
  3264. ; Buffer fuellen
  3265.          mov al,0
  3266.          mov dx,offset reader_fileName
  3267.          DOS OPEN_FILE
  3268.          jc  short @@empty
  3269.          push ax
  3270.          mov bx,ax
  3271.          mov dx,reader_file_pointer
  3272.          mov cx,reader_file_pointer+2
  3273.          PUSHR <dx,cx>
  3274.           add dx,READER_BUF_SIZE
  3275.           adc cx,0
  3276.           mov reader_file_pointer,dx
  3277.           mov reader_file_pointer+2,cx
  3278.          POPR  <cx,dx>
  3279.          mov al,0                   ; offset from start
  3280.          DOS MOVE_FILE_POINTER
  3281.          pop bx                     ; handle
  3282.          mov cx,READER_BUF_SIZE
  3283.          mov dx,offset reader_buf
  3284.          DOS READ_FROM_HANDLE
  3285.          push ax
  3286.          DOS CLOSE_FILE
  3287.          pop ax
  3288.          cmp ax,0
  3289.          jz  short @@empty
  3290.  
  3291.  ; buffer erfolgreich gefuellt
  3292.          mov reader_empty_flag,FALSE
  3293.          mov reader_buf_entries,ax
  3294.          mov reader_buf_ptr,offset reader_buf
  3295.  
  3296. @@do_read:
  3297.          mov bx,reader_buf_ptr
  3298.          mov al,[bx]
  3299.          inc bx
  3300.          mov reader_buf_ptr,bx
  3301.          dec reader_buf_entries
  3302.          jmp short @@exit
  3303. @@empty:
  3304.        mov reader_empty_flag,TRUE
  3305.        mov al,CPM_EOF
  3306.        mov bx,0ffffh       ; hl=FFFF  == Dos File Ende
  3307.        ret
  3308. @@exit:
  3309.        mov bx,0            ; a=hl=gelesenes byte
  3310.        mov bl,al
  3311.        ret
  3312. filereader endp
  3313.  
  3314. readstat proc
  3315.        mov al,0
  3316. ; the following is commented out because else
  3317. ; ccp cancels operations if input is read from bat
  3318. ; and al=ff
  3319. ;       cmp reader_empty_flag,TRUE
  3320.  ;      jz short @@exit
  3321.   ;     dec al
  3322. @@exit:
  3323.        ret
  3324. readstat endp
  3325.  
  3326. ; In:  ah=drive
  3327. ;      al=offset im dpb
  3328. ; Out: bx=word dpb[al]
  3329.  
  3330. get_dpb_entrie proc
  3331.        push si
  3332.        mov  bl,ah
  3333.        call get_dph_adr           ; bx:=dph
  3334.        xor  ah,ah
  3335.        mov  si,ax
  3336.        mov  bx,[es:bx+10]         ; bx:=dpb
  3337.        mov  bx,[es:bx+si]         ; bx:=dpb[ax]
  3338.        pop  si
  3339.        ret
  3340. get_dpb_entrie endp
  3341.  
  3342. ;
  3343. ; select disk in register c
  3344. ;
  3345. seldsk proc
  3346.        cmp cl,NDISKS-1
  3347.        mov bx,0000h               ; 0 = Drive nicht existent
  3348.        ja  short @@exit
  3349.    if HARD_DISC_TOO
  3350.        cmp cl,HARD_DISC
  3351.        jnz short @@no_hd
  3352.        cmp hd_handle,0
  3353.        mov bx,0
  3354.        jz  short @@exit
  3355.        jmp short @@noswp
  3356. @@no_hd:
  3357.    endif
  3358.        cmp drv_swap_flag,TRUE
  3359.        jnz short @@noswp
  3360.        mov bl,cl
  3361.        mov cl,1
  3362.        sub cl,bl
  3363. @@noswp:
  3364.        mov diskno,cl
  3365.        mov bl,cl
  3366.        call get_dph_adr
  3367. @@exit:
  3368.        ret
  3369. seldsk endp
  3370.  
  3371. ;  In:  bl:=Drive #
  3372. ;  Out: bx:= disk parameter header address
  3373. ;
  3374. get_dph_adr proc
  3375.        mov bh,0                   ; high order zero
  3376.        push cx
  3377.        LOG2(16)                   ; nach cl
  3378.        sal bx,cl                  ; bx*=16 (size of each header)
  3379.        pop cx
  3380.        add bx,offset dph_base+ZBIOSDISPL
  3381.        ret                        ;hl=.dph_base(diskno*16)
  3382. get_dph_adr endp
  3383.  
  3384. ;
  3385. ;  move to the track 00 position of current drive
  3386. ;  translate this call into a settrk call with parameter 00
  3387. ;
  3388. home proc
  3389.        mov cx,0                   ; select track 0
  3390.        call settrk
  3391.        mov  home_flag,TRUE        ; zur Auswertung durch read_track
  3392.        ret
  3393. home endp
  3394.  
  3395. ;
  3396. ; set track given by register bc
  3397. ;
  3398. settrk proc
  3399.        mov word ptr track,cx
  3400.        ret
  3401. settrk endp
  3402. ;
  3403. ; set sector given by register bc
  3404. ;
  3405. setsec proc
  3406.        mov word ptr sector,cx
  3407.        ret
  3408. setsec endp
  3409.  
  3410. ;
  3411. ;translate the sector given by bc using the
  3412. ;translate table given by de
  3413. ;
  3414. sectran proc
  3415.  
  3416.        mov  bx,cx
  3417.        or   dx,dx                 ; table ptr == 0 ?
  3418.        jz   short @@exit
  3419.        add  cx,cx                 ; index *= 2
  3420.        mov  bx,dx                 ; hl=trans
  3421.        add  bx,cx
  3422.        mov  bx,[es:bx]            ;hl=trans[sector]
  3423. @@exit:
  3424.        ret                        ;with value in hl
  3425. sectran endp
  3426. ;
  3427. ; set dma address given by registers b und c
  3428. ;
  3429. setdma proc
  3430.        mov dmaad,cx
  3431.        ret
  3432. setdma endp
  3433.  
  3434.  
  3435. calcadr proc
  3436. ;
  3437. ; ax:bx := record adresse in Ramdisk
  3438. ; illegal sec: cy
  3439. ;
  3440. ; 1. 64k track  0..15
  3441. ; 2. 64k track 16..31
  3442. ; ..
  3443.        mov al,track
  3444.        cmp al,lasttrack_rd
  3445.        ja short @@badrec
  3446.  
  3447.        mov al,sector
  3448.        cmp al,LAST_SEC1
  3449.        ja short @@badrec
  3450.  
  3451. ; phys recordnum = track * spt + sector
  3452.  
  3453.        PUSHR <cx,dx>
  3454.        mov  ah,RMD
  3455.        mov  al,0                  ; spt
  3456.        call get_dpb_entrie
  3457.        mov  cx,bx                 ; cx:=spt B:
  3458.        mov  ax,word ptr track
  3459.        mul  cx
  3460.        add  ax,word ptr sector    ; ax:=phys record num
  3461.        mov  cx,512                ; 64K = 512 records @ 128 Bytes
  3462.        mov  dx,0
  3463.        div  cx                    ; ax:= # of 64K, dx:=recordnum
  3464.        mov  cx,1000h
  3465.        push dx
  3466.        mul  cx
  3467.        pop  dx
  3468.        mov  bx,rdseg_adr
  3469.        add  bx,ax
  3470.        mov  ax,dx
  3471.        LOG2(RECORD_LEN)
  3472.        shl  ax,cl
  3473.        xchg bx,ax
  3474.        POPR <dx,cx>
  3475.       clc
  3476. @@exit:
  3477.       ret
  3478. @@badrec:
  3479.       stc
  3480.       jmp short @@exit
  3481. calcadr endp
  3482.  
  3483. ;
  3484. read proc
  3485. ;
  3486. ; lies einen record von 128 bytes
  3487. ;
  3488. if HARD_DISC_TOO
  3489.   cmp  diskno,HARD_DISC
  3490.   jnz short @@no_hd
  3491.   call read_hdisc
  3492.   mov al,0
  3493.   ret
  3494. @@no_hd:
  3495. endif
  3496.        cmp  diskno,RMD
  3497.        jnz  short @@rfdisc
  3498.        call calcadr               ; ax:bx := record addresse
  3499.        jc   short @@badsec
  3500.        call rdrec
  3501. @@exit:xor al,al                  ; o.k.
  3502.        ret
  3503. @@badsec:
  3504.        mov al,1
  3505.        ret
  3506.  
  3507. @@rfdisc:
  3508.        call is_valid_rec          ; ax=rec/sec
  3509.        jc   short @@badsec
  3510.  
  3511.        call read_track
  3512.        jc   short @@badsec
  3513. ;
  3514. ; record num ist in ah
  3515. ; ax:bx := adresse Track Buffer
  3516. ;
  3517.        mov  al,READ_OP
  3518.        call get_adr_in_buf        ; nach bx
  3519.        mov  ax,ds                 ; ax := seg track buffer
  3520.        call rdrec
  3521.        jmp  short @@exit
  3522.  
  3523.  
  3524. read endp
  3525.  
  3526. if HARD_DISC_TOO
  3527.  
  3528. read_hdisc proc
  3529.      mov ah,READ_FROM_HANDLE
  3530.      jmp short rw_hdisc
  3531. read_hdisc endp
  3532.  
  3533. write_hdisc proc
  3534.      push cx
  3535.      mov ah,WRITE_TO_HANDLE
  3536.      call rw_hdisc
  3537.      pop cx
  3538.      cmp cl,1
  3539.      jnz short @@exit
  3540. ; with cl=1 bdos has signaled that this is a write to directory (=file
  3541. ; close), so flush msdos file
  3542.  
  3543.        mov bx,hd_handle
  3544.        DOS DUPLICATE_HANDLE  ; to flush the file
  3545.        CALLC disp_disk_err
  3546.        mov bx,ax
  3547.        DOS CLOSE_FILE
  3548. @@exit:
  3549.      ret
  3550. write_hdisc endp
  3551.  
  3552. rw_hdisc proc
  3553.        PUSHA
  3554.        call @@rw_sec
  3555.        POPA
  3556.        ret
  3557.  
  3558. @@rw_sec:
  3559.  
  3560. ; phys recordnum = track * spt + sector
  3561.        push ax
  3562.        mov  ah,HARD_DISC
  3563.        mov  al,0                  ; spt
  3564.        call get_dpb_entrie
  3565.        mov  cx,bx                 ; cx:=spt B:
  3566.        mov  ax,word ptr track
  3567.        mul  cx
  3568.        add  ax,word ptr sector    ; ax:=phys record num
  3569.  
  3570.        mov  cx,0
  3571.        mov  dx,ax                 ; cx:dx *= 128
  3572.        rept 7  ; 128 = 2^7
  3573.         shl dx,1
  3574.         rcl cx,1
  3575.        endm
  3576.  
  3577.        mov al,0              ; seek from start
  3578.        mov bx,hd_handle
  3579.        DOS MOVE_FILE_POINTER ; cx:dx := file length
  3580.  
  3581.        pop ax
  3582.        mov dx,dmaad
  3583.        mov bx,hd_handle
  3584.        push ds
  3585.        push es
  3586.        pop ds
  3587.        mov cx,128            ; read/write one record
  3588.        int 21h
  3589.        pop ds
  3590. @@exit:
  3591.        ret
  3592. rw_hdisc endp
  3593. endif
  3594.  
  3595.  
  3596.  
  3597. ; berechne Sektoradresse im Buffer
  3598. ; a=sector*128+buf
  3599. ; input: al=READ_OP / WRITE_OP
  3600.  
  3601. get_adr_in_buf proc
  3602.       PUSHR <AX,CX>
  3603.        call is_dir_track
  3604.        mov  bx,offset dirtrbuf
  3605.         jz  short @@calc
  3606.        mov  bx,offset secbuf
  3607.        cmp  al,READ_OP
  3608.         jz  short @@calc
  3609.        mov  bx,offset wrtbuf
  3610. @@calc:
  3611.        xor  ax,ax
  3612.        mov  al,sector
  3613.        LOG2(RECORD_LEN)                  ; nach cl
  3614.        shl  ax,cl                 ; ax *= 128
  3615.        add  bx,ax
  3616.       POPR <CX,AX>
  3617.       RET
  3618. get_adr_in_buf endp
  3619.  
  3620. is_dir_track proc
  3621.       push ax
  3622.        mov  al,track
  3623.        cmp  al,dirtrack
  3624.       pop  ax
  3625.       ret
  3626. is_dir_track endp
  3627.  
  3628. ;
  3629. ;
  3630. ;
  3631. is_valid_rec proc
  3632. ; Out:  cy   sector illegal
  3633. ;
  3634. ; test auf gueltigen track/sector auf DISC
  3635. ;
  3636. COMMENT *
  3637.       mov al,track
  3638.       cmp al,LAST_TRCK0
  3639.       stc
  3640.       ja  short @@exit
  3641.       mov al,sector
  3642.       cmp al,LAST_SEC0
  3643.       stc
  3644.       ja short @@exit
  3645. ; ok, clear cy
  3646. *
  3647.       clc
  3648. @@exit:
  3649.       ret
  3650. is_valid_rec endp
  3651.  
  3652. ;
  3653. ; lies ganzen Track, falls noch nicht im Speicher
  3654. ;
  3655. read_track proc
  3656. ;
  3657. ; Error: cy=1
  3658. ;
  3659.       PUSHR <ax,bx,cx,dx>
  3660.  
  3661. ; der DirTrack wird nur gelesen nach HOME
  3662.  
  3663.       mov  al,track
  3664.       cmp  al,dirtrack
  3665.       jnz  short @@nodir
  3666.       TSTNCLR home_flag
  3667.       mov  bx,offset dirtrbuf
  3668.       jnz  short @@read_dir_track
  3669.       clc
  3670.       jmp short @@exit
  3671. @@nodir:
  3672.        cmp  al,last_track_read
  3673.        jz   short @@exit
  3674.  
  3675.            mov  bx,offset secbuf
  3676.            mov  last_track_read,al
  3677. @@read_dir_track:
  3678.            mov  r_track,al
  3679.  
  3680.            call read_phys_track
  3681.            ; ab jetzt CY nicht mehr veraendern !
  3682.  
  3683. @@exit:
  3684.       POPR <dx,cx,bx,ax>
  3685.       ret
  3686. read_track endp
  3687.  
  3688. ;
  3689. ; lies ganzen Track, in den geschrieben werden soll, ein,
  3690. ;  falls noch nicht im Speicher
  3691. ;
  3692. read_w_track proc
  3693. ;
  3694. ; Error: cy=1
  3695. ;
  3696.       PUSHR <ax,bx,cx,dx>
  3697.       ; der DirTrack ist sowieso im Speicher und braucht
  3698.       ; nicht gelesen werden
  3699.       mov  al,track
  3700.       cmp  al,dirtrack
  3701.       jz  short @@exit
  3702.  
  3703.       cmp  al,last_track_written
  3704.       jz   short @@exit
  3705.  
  3706.       ; falls noetig alten Track im WriteBuffer erst
  3707.       ; ausschreiben
  3708.       call write_out_old_track
  3709.  
  3710.       mov  al,track
  3711.       mov  bx,offset wrtbuf
  3712.       mov  last_track_written,al
  3713.       mov  r_track,al
  3714.       call read_phys_track
  3715.  
  3716.       ; ab jetzt CY nicht mehr veraendern !
  3717.  
  3718. @@exit:
  3719.       POPR <dx,cx,bx,ax>
  3720.       ret
  3721. read_w_track endp
  3722.  
  3723. ; physikalische Sektorlaenge herstellen
  3724. dos_phys_len proc
  3725.        PUSHR <es,ax,di>
  3726.        mov  ax,0
  3727.        mov  es,ax
  3728.        les  di,[es:78h]
  3729.        mov  al,ms_phys_sec_len
  3730.        mov  es:[di+3],al
  3731.        POPR <di,ax,es>
  3732.        ret
  3733. dos_phys_len endp
  3734.  
  3735.  
  3736. ; INT 1E - Disk Initialization Parameter Table Vector
  3737. ; far pointer to the diskette base table
  3738.  
  3739. ; unfortunately this points to ROM within a os/2 vdm
  3740. ; so it cannot be changed
  3741. ; (maybe it could be copied to ram)
  3742.  
  3743. ; physikalische Sektorlaenge herstellen
  3744. cpm_phys_len proc
  3745.        PUSHR <es,ax,di>
  3746.        mov  ax,0
  3747.        mov  es,ax
  3748.        les  di,[es:1Eh*4]
  3749.        mov  al,cpm_phys_sec_len
  3750.        mov  es:[di+3],al
  3751.        POPR <di,ax,es>
  3752.        ret
  3753. cpm_phys_len endp
  3754.  
  3755. rw_phys_track proc  ; common for read and write
  3756. ; in: bp low: fn # for int 13
  3757. ;     bp high: track to read/write
  3758. ; bx: buf offset
  3759.       PUSHR <ax,bx,cx,dx>
  3760.  
  3761.       mov  cl,retry_count
  3762.       xor  ch,ch
  3763. @@tryrw:
  3764.         call cpm_phys_len
  3765.         push es
  3766.         mov  ax,emudata_seg
  3767.         mov  es,ax                ; ist sonst z80cpu_seg
  3768.         push cx
  3769.  
  3770.           mov  dl,cpm_drive       ; diskno
  3771.           mov  dh,side
  3772.           mov  cx,bp              ; Track
  3773.           call track_trans
  3774.           mov  cl,first_phys_sec  ; physical sector number
  3775.           mov  ax,bp              ; op code to al
  3776.           mov  ah,al
  3777.           mov  al,phys_sec_pt     ; lies ganzen Track auf einmal
  3778.           int 13h                 ; es:bx := track
  3779.         pop cx
  3780.         pop es
  3781.         call dos_phys_len
  3782.         jnc  short @@exit
  3783.         cmp  ah,9
  3784.         jz   dma_bound
  3785. ; Fehler, Disk Reset und nochmal versuchen
  3786.         mov ah,0
  3787.         mov dl,cpm_drive
  3788.         int 13h                   ; disk reset
  3789.       loop  @@tryrw
  3790.       stc                         ; Error, cy
  3791. @@exit:
  3792.       POPR <dx,cx,bx,ax>
  3793.       ret
  3794. rw_phys_track endp
  3795.  
  3796.  
  3797. read_phys_track proc
  3798.  
  3799. ; der naechste Test sollte eigentlich nicht noetig sein, aber
  3800. ; mein 386 Ami Bios weigert sich sonst, den gleichen Track nochmal
  3801. ; zu lesen; jedenfalls kann auch gleich ein Diskwechsel festgestellt
  3802. ; werden
  3803.       call tst_disk_change
  3804.       MOVNZ  last_track_read,0ffh
  3805.  
  3806.       PUSHR <bp>
  3807.  
  3808.        mov  ah,r_track
  3809.        mov  al,2        ; read sector
  3810.        mov  bp,ax
  3811.        call rw_phys_track
  3812.  
  3813.       POPR <bp>
  3814.       ret
  3815. read_phys_track endp
  3816.  
  3817.  
  3818. write_phys_track proc
  3819.       PUSHR <bx,bp>
  3820.  
  3821.        mov  bx,outbuf_ptr
  3822.        mov  ah,w_track
  3823.        mov  al,3        ; write sector
  3824.        mov  bp,ax
  3825.        call rw_phys_track
  3826.  
  3827.       POPR <bp,bx>
  3828.       ret
  3829. write_phys_track endp
  3830.  
  3831.  
  3832. ; Trackuebersetzung nur fuer CP/M 86 DS DD noetig
  3833. ; muss vor phys. read/write Ops aufgerufen werden
  3834. ;
  3835. ; in: ch: zu uebersetzender Track
  3836. ;     dh: Disk Side
  3837.  
  3838. track_trans proc
  3839.           cmp  ch,phys_tracks
  3840.           jb  short @@exit
  3841.           cmp  cpm86dd_flag,TRUE
  3842.           jnz short @@nocpm86dd
  3843.           push ax
  3844.           mov  al,ch
  3845.           mov  ch,79
  3846.           sub  ch,al
  3847.           pop  ax
  3848.           inc  dh                 ; Seite 1
  3849.           jmp  short @@exit
  3850. @@nocpm86dd:
  3851.           sub ch,40
  3852.           inc  dh                 ; Seite 1
  3853. @@exit:
  3854.           ret
  3855. track_trans endp
  3856.  
  3857. tst_disk_change proc
  3858.           PUSHR <ax,dx>
  3859.           cmp hd_drive_flag,FALSE
  3860.           jz  short @@exit        ; kein Diskwechsel => Z
  3861.           mov ah,16h
  3862.           mov dl,cpm_drive
  3863.           int 13h  ; Test auf Wechsel
  3864.           cmp ah,0                ; kein Diskwechsel => Z
  3865. @@exit:
  3866.           POPR <dx,ax>
  3867.           ret
  3868. tst_disk_change endp
  3869.  
  3870. ; falls noch nicht geschriebener Track im Speicher ist,
  3871. ; der kein DirTrack ist, ausschreiben
  3872.  
  3873. write_out_old_track proc
  3874.       cmp  write_flag,TRUE
  3875.       jnz short @@exit
  3876.       mov  al,last_track_written
  3877.       mov  w_track,al
  3878.       mov  outbuf_ptr,offset wrtbuf
  3879.         call write_phys_track
  3880.       mov  write_flag,FALSE
  3881. @@exit:
  3882.       ret
  3883. write_out_old_track endp
  3884.  
  3885. ;
  3886. ; den Dir Track auf Disk schreiben
  3887. ;
  3888. write_out_dir proc
  3889.       call write_out_old_track    ; falls noetig
  3890.       mov  al,dirtrack
  3891.       mov  w_track,al
  3892.       mov  outbuf_ptr,offset dirtrbuf
  3893.           call write_phys_track
  3894.       ret
  3895. write_out_dir endp
  3896.  
  3897. ;
  3898. ; versuchen, richtiges physikalisches Format zu finden
  3899. ; und disc parameter block herrichten
  3900. ;
  3901. ; falls autologin_flag = FALSE , kann das Zeitaufwendige login
  3902. ; entfallen
  3903.  
  3904. login_disc proc
  3905.       push bx
  3906.       call tst_hd_drive
  3907.       invalidate_rdbuf            ; Track Buffer auf leer setzen
  3908.                                   ; damit bei read_track gelesen wird
  3909.       mov write_flag,FALSE        ; sonst wird beim naechsten write
  3910.                                   ; erst alter Schrott ausgeschrieben
  3911.       cmp  autologin_flag,TRUE
  3912.       jnz  @@exit
  3913.       cmp  cpmdrv_set_flg,TRUE
  3914.       jz short @@no_drset
  3915.       mov  cpm_drive,PHYS_DRV
  3916. @@no_drset:
  3917.       mov  al,ms_phys_sec_len
  3918.       mov  cpm_phys_sec_len,al
  3919.  
  3920.       mov cpm86dd_flag,FALSE
  3921.  
  3922.       mov retry_count,2           ; Leseversuche herabsetzen,
  3923.                                   ; damit bei falschem
  3924.                                   ; Format nicht zuviel Zeit verschwendet wird
  3925.  
  3926. @@loop:
  3927.  
  3928.        cmp breakflag,TRUE
  3929.  
  3930.        CALLZ  prg_exit
  3931.  
  3932. ; erst mal mit dem zuletzt verwendeten Format versuchen
  3933. ; aber nicht, wenn letztes CP/M 86 war, da sonst das
  3934. ; aehnliche Format mit 9 Sektoren nicht erkannt wird
  3935.  
  3936.       cmp byte ptr phys_sec_pt,8
  3937.       jz  short @@tst_cpm86
  3938.  
  3939.       mov al,pspt_last
  3940.       mov phys_sec_pt,al
  3941.       mov al,phys_tracks_last
  3942.       mov phys_tracks,al
  3943.       mov al,frstps_last
  3944.       mov first_phys_sec,al       ; physical sector
  3945.       mov al,dirtr_last
  3946.       mov dirtrack,al
  3947.       inc al
  3948.       mov r_track,al
  3949.       mov bx,offset secbuf
  3950.       call read_phys_track
  3951.       mov  bx,dpb_last
  3952.       jnc  @@goodfmt
  3953.  
  3954.  
  3955. ;
  3956. ; CP/M 86 format ?
  3957. ;
  3958. ; Bedingungen: Seite 0 muss Sektoren 1-8 haben, aber nicht 1-9
  3959. ;              Seite 1 muss Sektoren 1-8 haben
  3960.  
  3961. ; setze 9 Phys. Sektoren, bei cp/m 86 mit 8 Sektoren pro Track muss
  3962. ; es einen Lesefehler geben
  3963.  
  3964. @@tst_cpm86:
  3965.       mov phys_sec_pt,9
  3966.       mov phys_tracks,40
  3967.       mov first_phys_sec,1h
  3968.       mov r_track,1+1
  3969.       mov dirtrack,1
  3970.       mov bx,offset secbuf
  3971.       call read_phys_track
  3972.       jnc  short @@nocpm86
  3973.  
  3974.       mov phys_sec_pt,8
  3975.       mov phys_tracks,40
  3976.       mov first_phys_sec,1h
  3977.       mov r_track,1+1
  3978.       mov dirtrack,1
  3979.       mov bx,offset secbuf
  3980.       call read_phys_track
  3981.       jc  short @@nocpm86
  3982.  
  3983.  
  3984.   ; Teste noch Seite 2 mit SektorNummer > 39
  3985.  
  3986.       mov phys_sec_pt,8
  3987.       mov phys_tracks,40
  3988.       mov first_phys_sec,1h
  3989.  
  3990.       mov r_track,40
  3991.       mov dirtrack,1
  3992.       mov bx,offset secbuf
  3993.       call read_phys_track
  3994.       mov  bx,offset dpb_cpm86DS
  3995.       mov  cpm86dd_flag,TRUE
  3996.       jnc  @@goodfmt
  3997.       mov  cpm86dd_flag,FALSE
  3998.       mov  bx,offset dpb_cpm86SS
  3999.       jmp  @@goodfmt
  4000.  
  4001. @@nocpm86:
  4002.  
  4003. ;
  4004. ; cpc system format ?
  4005. ;
  4006.       mov phys_sec_pt,9
  4007.       mov phys_tracks,40
  4008.       mov first_phys_sec,41h
  4009.       mov r_track,2+1
  4010.       mov dirtrack,2
  4011.       mov bx,offset secbuf
  4012.       call read_phys_track
  4013.       mov  bx,offset dpb_cpc
  4014.       jnc  short @@goodfmt
  4015. ;
  4016. ; data format ?
  4017. ;
  4018.       mov phys_sec_pt,9
  4019.       mov phys_tracks,40
  4020.       mov first_phys_sec,0c1h
  4021.       mov r_track,0+1
  4022.       mov dirtrack,0
  4023.       mov bx,offset secbuf
  4024.       call read_phys_track
  4025.       mov  bx,offset dpb_dta
  4026.       jnc  short @@goodfmt
  4027.  
  4028. @@tsteigfrm:
  4029. ;
  4030. ; is it own format
  4031. ;
  4032.       mov phys_sec_pt,9
  4033.       mov phys_tracks,40
  4034.       mov first_phys_sec,1
  4035.       mov r_track,0+1
  4036.       mov dirtrack,0
  4037.       mov bx,offset secbuf
  4038.       call read_phys_track
  4039.       mov  bx,offset dpb_eig
  4040.       jnc  short @@goodfmt
  4041.  
  4042. @@badfmt:
  4043.       mov  bx,offset bad_format
  4044.       call puts
  4045.       call crtin
  4046.       cmp  autologin_flag,TRUE    ; waehrend conin kann Edit DPH gewes. sein
  4047.       jnz  short @@exit
  4048.       jmp  @@loop
  4049.  
  4050. @@goodfmt:
  4051.  
  4052. ; physikalisches Format merken
  4053.  
  4054.        mov al,phys_sec_pt
  4055.        mov pspt_last,al
  4056.        mov al,first_phys_sec
  4057.        mov frstps_last,al
  4058.        mov al,dirtrack
  4059.        mov dirtr_last,al
  4060.        mov dpb_last,bx
  4061.  
  4062.        mov  si,bx
  4063.        mov  di,offset dpb0+ZBIOSDISPL
  4064.        mov  cx,size dpb
  4065.        cld
  4066.        rep movsb                  ; es:di := ds:si
  4067.  
  4068. @@exit:
  4069.        pop bx
  4070.        mov retry_count,5
  4071.        ret
  4072. login_disc endp
  4073.  
  4074.  
  4075. write proc
  4076. ;
  4077. ; write a record of 128 bytes
  4078. ;
  4079. if HARD_DISC_TOO
  4080.   cmp  diskno,HARD_DISC
  4081.   jnz short @@no_hd
  4082.   call write_hdisc
  4083.   mov al,0
  4084.   ret
  4085. @@no_hd:
  4086. endif
  4087.        cmp  diskno,RMD
  4088.        jnz  short wtodisc
  4089.        call calcadr               ; ax:bx := record adress
  4090.        jc   short @@bad
  4091.        call wrtrec                ; buffer := record
  4092.        jc   short @@bad
  4093.        xor  al,al                 ; write ok
  4094.        ret
  4095. @@bad: mov al,1
  4096.        ret
  4097. write endp
  4098.  
  4099. wtodisc proc
  4100.        push cx
  4101.        call is_valid_rec          ; ax=rec/sec
  4102.        pop  cx
  4103.        jc   short @@badsec
  4104.  
  4105.  
  4106. ; if track noch nicht im Buffer
  4107. ;    if noch alter Track im Buffer
  4108. ;       alten Track ausschreiben
  4109. ;    endif
  4110. ;    lies neuen Track ein
  4111. ; endif
  4112. ; if track ist dirtrack
  4113. ;    if noch alter Track im Buffer
  4114. ;       alten Track ausschreiben
  4115. ;    endif
  4116. ;    dirtrack ausschreiben
  4117. ; else
  4118. ;    Setze Flag, daß Sektor geschreiben wurde
  4119. ; endif
  4120. ;
  4121.  
  4122.        push cx                    ; bdos info, ob dirsectoren
  4123.        call read_w_track
  4124.        pop  cx
  4125.        jc   short @@badsec
  4126. ;
  4127. ; record # ist in ah
  4128. ;
  4129.  
  4130.        push cx
  4131.        mov  al,WRITE_OP
  4132.        call get_adr_in_buf
  4133.        mov  ax,ds                 ; ax:= seg track buffer
  4134.        call wrtrec
  4135.        pop  cx
  4136.        cmp  cl,1
  4137.        jz   short @@isdir1
  4138.        call is_dir_track
  4139.        jz   short @@isdir1
  4140.  
  4141.        mov  write_flag,TRUE
  4142.        mov  al,track
  4143.        mov  last_track_written,al
  4144.        mov  al,0                  ; o.k.
  4145.        jmp  short @@exit
  4146.  
  4147. @@isdir1:
  4148.        call write_out_dir
  4149.        jc short @@badsec
  4150.        mov  al,0
  4151.        jmp  short @@exit
  4152. @@badsec:
  4153.       mov al,1
  4154. @@exit:
  4155.       ret
  4156. wtodisc endp
  4157.  
  4158. ;
  4159. ; In: ax:bx = source adr
  4160. ;
  4161. rdrec proc
  4162. ;
  4163.        PUSHR <si,di,bx,cx,ax>
  4164.        push ds
  4165.          mov si,bx
  4166.          mov di,dmaad             ; ds MUSS =  emudata_seg sein
  4167.          mov ds,ax
  4168.          mov cx,RECORD_LEN/2             ; record laenge in words
  4169.          cld
  4170.          rep movsw                ; es:di := ds:si
  4171.        pop ds
  4172.        POPR <ax,cx,bx,di,si>
  4173.        ret
  4174. rdrec endp
  4175. ;
  4176. ; In: ax:bx=target adr
  4177. ;
  4178. wrtrec proc
  4179.        PUSHR <si,di,cx,ax>
  4180.        push es
  4181.        push ds
  4182.  
  4183.        mov si,dmaad               ; ACHTUNG: der MOV muss
  4184.                                   ; vor DS Segmentwechsel sein
  4185.        mov di,bx
  4186.        mov bx,ax                  ; ramdisc
  4187.        mov ax,es                  ; cp/m
  4188.        mov es,bx
  4189.        mov ds,ax
  4190.  
  4191.        mov cx,RECORD_LEN/2               ; record laenge in words
  4192.        cld
  4193.        rep movsw                  ; es:di := ds:si
  4194.        pop ds
  4195.        pop es
  4196.        POPR <ax,cx,di,si>
  4197.        ret
  4198. wrtrec endp
  4199.  
  4200. emulator_seg ends
  4201.  
  4202.  
  4203. end init
  4204.